在MySQL中给出这个SQL查询:
SELECT * FROM tableA WHERE tableA.id IN (SELECT id FROM tableB);
MySQL是否为SELECT id FROM tableB
中的每一行多次执行子查询tableA
?
有没有办法在不使用变量或存储过程的情况下让sql更快?
为什么这通常比使用LEFT JOIN
慢?
答案 0 :(得分:8)
你的假设是假的;子查询只执行一次。它比连接慢的原因是因为IN
无法利用索引;每次评估WHERE
子句时,它必须扫描一次参数,即tableA中每行一次。您可以在不使用变量或存储过程的情况下优化查询,只需将IN
替换为连接,即可:
SELECT tableA.field1, tableA.field2, [...]
FROM tableA
INNER JOIN tableB ON tableA.id = tableB.id
除非你不介意从两个表中取回每个字段,否则你需要在SELECT
子句中枚举你想要的字段;例如,tableA.*
将引发语法错误。
答案 1 :(得分:3)
首先,这取决于MySQL的版本。我相信5.6版正确地优化了这些查询。 MySQL文档与此不一致。例如,here它说了一件事:
考虑以下子查询比较:
outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)
MySQL“从外到内评估查询。”也就是说,它首先进行评估 获取外部表达式outer_expr的值,然后运行 子查询并捕获它产生的行。
这个“从外到内”意味着对每一行评估子查询。这与我使用MySQL的经验一致。
文档另有说明here:
MySQL本身的一些优化是:
- MySQL只执行一次不相关的子查询。使用EXPLAIN确保给定的子查询确实不相关。
- MySQL重写IN,ALL,ANY和SOME子查询,试图利用子查询中的select-list列被编入索引的可能性。
我认为语句不引用in
条款。也许会发生的事情是子查询被重写为相关子查询以检查索引,然后它被多次运行(无论是否存在索引)。