哪个MySQL JOIN查询更有效?

时间:2009-11-12 22:28:28

标签: sql mysql

给出以下表结构:

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)
);

哪种联接查询更有效:#1,

SELECT u.name FROM user u INNER JOIN user_profile p ON u.uid = p.uid WHERE p.address = 'some constant'

或#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

效率差异有多大?

4 个答案:

答案 0 :(得分:7)

第一种语法通常更有效。

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'

第二次查询:

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'

如您所见,在第二种情况下只使用了索引的一部分,并且q被强制引导。

<强>更新

派生查询(这个问题关注的问题)不要与子查询混淆

虽然MySQL无法优化派生查询FROM子句中使用的那些),但子查询(与{一起使用的那些) {1}}或IN)的待遇要好得多。

有关详细信息,请参阅我博客中的这些文章:

答案 1 :(得分:1)

查看这些选择的解释查询,我们得到:(行标题是id,select_type,table,type,possible_keys,key,key_len,ref,rows,extra)

1   SIMPLE  u   system  PRIMARY NULL    NULL    NULL    1   
1   SIMPLE  p   const   PRIMARY,address PRIMARY 4   const   1   

第二次探索......

1   PRIMARY u   system  PRIMARY NULL    NULL    NULL    1   
1   PRIMARY <derived2>  system  NULL    NULL    NULL    NULL    1    
2   DERIVED p   ref address address 201     1   Using where

因此,第一个查询更简单,更简单通常更有效。

但是,从您的CREATE中,将地址字段添加到用户表会更加高效。由于配置文件与用户表(在uid上)是1对1,因此可以组合表并仍然保持架构规范化。

然后,您的查询将是

SELECT u.name FROM user u WHERE u.address = 'some constant'

,解释显示

1   SIMPLE  u   ref address address 201 const   1   Using where, using filesort

奇怪的是,简化的模式使用了文件排序,如果你有很多行,那就很糟糕。

更多解释:http://dev.mysql.com/doc/refman/5.0/en/explain.html

答案 2 :(得分:0)

不确定MySQL的查询引擎将如何处理,但我的假设是第一个查询会表现更好,效率更高。

第一个查询也更标准,因此更容易阅读,因此更为可取。

答案 3 :(得分:0)

答案通常取决于数据库收集的统计数据。第一种形式对优化器来说似乎更容易。

据我所知,MySQL不适用于IN ...查询和子选择