因未使用的内连接而选择慢

时间:2015-05-01 07:38:42

标签: mysql sql inner-join innodb

我有两张桌子:

explain select count(*) FROM B inner join A on B.a_id = A.id WHERE B.c_id = 7;
+----+-------------+-------+--------+-----------------------+------------+---------+--------------------+--------+-------------+
| id | select_type | table | type   | possible_keys         | key        | key_len | ref                | rows   | Extra       |
+----+-------------+-------+--------+-----------------------+------------+---------+--------------------+--------+-------------+
|  1 | SIMPLE      | B     | ref    | IX_a_id,IX_c_id       | IX_c_id    | 4       | const              | 116624 | Using where |
|  1 | SIMPLE      | A     | eq_ref | PRIMARY               | PRIMARY    | 4       | test1.B.a_id       |      1 | Using index |
+----+-------------+-------+--------+-----------------------+------------+---------+--------------------+--------+-------------+

他们各有几百万行。

select count(*) from B where B.c_id = 7

现在,我无法理解为什么mysql无法忽略不需要的内部连接到A来杀死性能。即,以下查询等同于上述:

{{1}}

应该很容易推断,因为B.a_id不能为空,而B.a_id对唯一键有一个约束A.id

有没有办法让mysql理解这个?

2 个答案:

答案 0 :(得分:0)

包含连接的SQL语句将扫描两个表并在进行连接之前将它们加载到临时存储中。这意味着它将两个表加载到临时表中,对排除并删除不必要的重复项并返回结果。您可以通过使用子查询作为要加入的表来加快速度。

例如,如果您执行了以下操作,则不太可能获得性能损失:

select count(*) FROM 
(select * from B where B.c_id = 7 and B.a_id is not Null) as sub_b
inner join 
(select * from A where A.id is not Null) as sub_a
on (sub_b.a_id = sub_a.id);

这是因为SQL的行为正如您所期望的那样,并且预先过滤结果以进行连接,从而将较少的内容加载到其临时表中。您可以使用A上的id和B

上的c_id和a_id上的索引进一步加快速度

如果您有大量列,减少查询中返回的列数也会加快它的速度:

select count(sub_b.a_id) FROM 
(select a_id from B where B.c_id = 7 and B.a_id is not Null) as sub_b
inner join 
(select id from A where A.id is not Null) as sub_a
on (sub_b.a_id = sub_a.id);

---- ----编辑

下面提出了一个好点,第二个选择是不必要的。第一个子选择确保首先应用我们关心的where子句。

试试这个:

select count(sub_b.a_id) FROM 
(select a_id from B where B.c_id = 7) as sub_b
inner join A on (sub_b.a_id = A.id);

答案 1 :(得分:0)

  

现在,我无法理解为什么mysql无法忽略不需要的内部联接到A来杀死性能。

解决隐含的问题......

提交错误报告以建议此类优化。 http://bugs.mysql.com