给出以下表结构:
CREATE TABLE user (
uid INT(11) auto_increment,
name VARCHAR(200),
PRIMARY KEY(uid)
);
CREATE TABLE user_profile(
uid INT(11),
address VARCHAR(200),
PRIMARY KEY(uid),
INDEX(address)
);
Run Code Online (Sandbox Code Playgroud)
哪个连接查询更有效:#1,
SELECT u.name FROM user u INNER JOIN user_profile p ON u.uid = p.uid WHERE p.address = 'some constant'
Run Code Online (Sandbox Code Playgroud)
或#2:
SELECT u.name FROM user u INNER JOIN (SELECT uid FROM user_profile WHERE p.address = 'some constant') p ON u.uid = p.uid
Run Code Online (Sandbox Code Playgroud)
效率差异有多大?
第一种语法通常更有效.
MySQL缓冲派生查询,因此使用派生查询user_profile可能会成为连接中的驱动表.
即使user_profile是领先的,也应首先缓冲子查询结果,这意味着内存和性能影响.
一个LIMIT应用于查询将使第一个查询快得多这是不是第二个事实.
以下是样本计划.有一个索引(val, nid)的表t_source:
第一个查询:
EXPLAIN
SELECT *
FROM t_source s1
JOIN t_source s2
ON s2.nid = s1.id
WHERE s2.val = 1
1, 'SIMPLE', 's1', 'ALL', 'PRIMARY', '', '', '', 1000000, ''
1, 'SIMPLE', 's2', 'ref', 'ix_source_val,ix_source_val_nid,ix_source_vald_nid', 'ix_source_val_nid', '8', 'const,test.s1.id', 1, 'Using where'
Run Code Online (Sandbox Code Playgroud)
第二个查询:
EXPLAIN
SELECT *
FROM t_source s1
JOIN (
SELECT nid
FROM t_source s2
WHERE val = 1
) q
ON q.nid = s1.id
1, 'PRIMARY', '<derived2>', 'ALL', '', '', '', '', 100000, ''
1, 'PRIMARY', 's1', 'ref', 'PRIMARY', 'PRIMARY', '4', 'q.nid', 10000, 'Using where'
2, 'DERIVED', 's2', 'ref', 'ix_source_val,ix_source_val_nid,ix_source_vald_nid', 'ix_source_vald_nid', '4', '', 91324, 'Using index'
Run Code Online (Sandbox Code Playgroud)
如您所见,在第二种情况下只使用索引的一部分,并且q被强制引导.
更新:
派生查询(这个问题关注的问题)不应与子查询混淆.
虽然MySQL无法优化派生查询(在FROM子句中使用的查询),但子查询(与INor一起使用的查询EXISTS)的处理要好得多.
有关详细信息,请参阅我的博客中的这些文章
| 归档时间: |
|
| 查看次数: |
6900 次 |
| 最近记录: |