我有两张桌子:
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理解这个?
答案 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)