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

Rea*_*lar 3 mysql database-performance

鉴于MySQL中的这个SQL查询:

SELECT * FROM tableA WHERE tableA.id IN (SELECT id FROM tableB);
Run Code Online (Sandbox Code Playgroud)

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

有没有办法让sql更快,而不使用变量或存储过程?

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

Aar*_*ler 9

你的假设是假的; 子查询只执行一次.它比连接慢的原因是因为IN无法利用索引; 每次WHERE计算子句时,它必须扫描一次参数,即tableA中每行一次.您可以在不使用变量或存储过程的情况下优化查询,只需将其替换IN为连接,即:

SELECT tableA.field1, tableA.field2, [...]
FROM tableA 
  INNER JOIN tableB ON tableA.id = tableB.id
Run Code Online (Sandbox Code Playgroud)

除非你不介意从两个表中取回每个字段,否则你需要在SELECT子句中枚举你想要的字段; tableA.*例如,将引发语法错误.

  • +1."LEFT JOIN"也不是一回事.`INNER JOIN`就是答案. (3认同)
  • 你确定在 MySQL 中子查询只会执行一次吗?保证从何而来? (2认同)

Gor*_*off 5

首先,这取决于 MySQL 的版本。我相信 5.6 版可以正确优化此类查询。MySQL 文档对此不一致。例如,这里说了一件事:

考虑以下子查询比较:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)
Run Code Online (Sandbox Code Playgroud)

MySQL“从外到内”评估查询。也就是说,它首先获取外部表达式outer_expr 的值,然后运行子查询并捕获它产生的行。

这种“从外到内”意味着对每一行评估子查询。这与我使用 MySQL 的经验一致。

文档在这里另有建议:

MySQL 本身所做的一些优化是:

  • MySQL 只执行一次不相关的子查询。使用 EXPLAIN 来确保给定的子查询确实是不相关的。
  • MySQL 重写 IN、ALL、ANY 和 SOME 子查询以试图利用子查询中的选择列表列被索引的可能性。

我相信,语句也不会参考in条款。可能发生的情况是将子查询重写为相关子查询以检查索引,然后多次运行(无论是否存在索引)。