鉴于 MySQL 中的这个 SQL 查询:
SELECT * FROM tableA WHERE tableA.id IN (SELECT id FROM tableB);
SELECT id FROM tableB
MySQL 是否对中的每一行多次执行子查询tableA
?
有没有办法在不使用变量或存储过程的情况下让 sql 运行得更快?
为什么这通常比使用慢LEFT JOIN
?
鉴于 MySQL 中的这个 SQL 查询:
SELECT * FROM tableA WHERE tableA.id IN (SELECT id FROM tableB);
SELECT id FROM tableB
MySQL 是否对中的每一行多次执行子查询tableA
?
有没有办法在不使用变量或存储过程的情况下让 sql 运行得更快?
为什么这通常比使用慢LEFT JOIN
?
你的假设是错误的;子查询将只执行一次。它比连接慢的原因是因为IN
不能利用索引;每次WHERE
评估子句时,它必须扫描其参数一次,即 tableA 中的每行一次。您可以在不使用变量或存储过程的情况下优化查询,只需将 替换IN
为连接即可,因此:
SELECT tableA.field1, tableA.field2, [...]
FROM tableA
INNER JOIN tableB ON tableA.id = tableB.id
除非您不介意从两个表中取回每个字段,否则您确实需要在SELECT
子句中枚举您想要的字段;tableA.*
,例如,将引发语法错误。
首先,这取决于 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
条款。也许发生的情况是子查询被重写为相关子查询以检查索引,然后运行多次(无论是否存在索引)。