5

鉴于 MySQL 中的这个 SQL 查询:

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

SELECT id FROM tableBMySQL 是否对中的每一行多次执行子查询tableA

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

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

4

2 回答 2

10

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

SELECT tableA.field1, tableA.field2, [...]
FROM tableA 
  INNER JOIN tableB ON tableA.id = tableB.id

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

于 2013-09-13T16:16:08.507 回答
5

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

考虑以下子查询比较:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

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

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

文档在这里另有建议:

MySQL 本身进行的一些优化是:

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

我认为该声明并未提及in条款。也许发生的情况是子查询被重写为相关子查询以检查索引,然后运行多次(无论是否存在索引)。

于 2013-09-13T16:35:18.123 回答