MySQL IN子句是否多次执行子查询?

时间:2013-09-13 16:12:08

标签: mysql database-performance

在MySQL中给出这个SQL查询:

SELECT * FROM tableA WHERE tableA.id IN (SELECT id FROM tableB);

MySQL是否为SELECT id FROM tableB中的每一行多次执行子查询tableA

有没有办法在不使用变量或存储过程的情况下让sql更快?

为什么这通常比使用LEFT JOIN慢?

2 个答案:

答案 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条款。也许会发生的事情是子查询被重写为相关子查询以检查索引,然后它被多次运行(无论是否存在索引)。