开发仍在进行中,因此从长远来看,没有任何优化技巧是可靠的。下面的列表提供了一些您可能想要尝试的有趣技巧。另见 第 8.2.2 节,“优化子查询和派生表”。
使用影响子查询中行的数量或顺序的子查询子句。例如:
SELECT * FROM t1 WHERE t1.column1 IN (SELECT column1 FROM t2 ORDER BY column1); SELECT * FROM t1 WHERE t1.column1 IN (SELECT DISTINCT column1 FROM t2); SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 LIMIT 1);
用子查询替换连接。例如,试试这个:
SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN ( SELECT column1 FROM t2);
而不是这个:
SELECT DISTINCT t1.column1 FROM t1, t2 WHERE t1.column1 = t2.column1;
一些子查询可以转换为连接,以与不支持子查询的旧版本 MySQL 兼容。但是,在某些情况下,将子查询转换为连接可能会提高性能。请参阅 第 13.2.10.11 节,“将子查询重写为连接”。
将子句从外部移动到子查询内部。例如,使用此查询:
SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);
而不是这个查询:
SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);
再举一个例子,使用这个查询:
SELECT (SELECT column1 + 5 FROM t1) FROM t2;
而不是这个查询:
SELECT (SELECT column1 FROM t1) + 5 FROM t2;
使用行子查询而不是相关子查询。例如,使用此查询:
SELECT * FROM t1 WHERE (column1,column2) IN (SELECT column1,column2 FROM t2);
而不是这个查询:
SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t2.column1=t1.column1 AND t2.column2=t1.column2);
使用
NOT (a = ANY (...))
而不是a <> ALL (...)
。使用而不是。
x = ANY (
table containing (1,2)
)x=1 OR x=2
使用
= ANY
而不是EXISTS
。对于始终返回一行的不相关子查询,总是
IN
比 慢=
。例如,使用此查询:SELECT * FROM t1 WHERE t1.col_name = (SELECT a FROM t2 WHERE b = some_const);
而不是这个查询:
SELECT * FROM t1 WHERE t1.col_name IN (SELECT a FROM t2 WHERE b = some_const);
这些技巧可能会导致程序运行得更快或更慢。使用
BENCHMARK()
函数之类的 MySQL 工具,您可以了解在您自己的情况下有什么帮助。请参阅
第 12.16 节,“信息功能”。
MySQL本身做的一些优化是:
MySQL 只执行一次不相关的子查询。用于
EXPLAIN
确保给定的子查询确实是不相关的。MySQL 重写
IN
、ALL
、ANY
和SOME
子查询以试图利用子查询中的选择列表列被索引的可能性。MySQL 将以下形式的子查询替换为索引查找函数,该函数
EXPLAIN
描述为特殊的连接类型(unique_subquery
或index_subquery
):... IN (SELECT indexed_column FROM single_table ...)
MIN()
MySQL 使用涉及or 的表达式增强以下形式的表达式MAX()
,除非 涉及NULL
值或空集:value {ALL|ANY|SOME} {> | < | >= | <=} (uncorrelated subquery)
例如,这个
WHERE
条款:WHERE 5 > ALL (SELECT x FROM t)
优化器可能会这样处理:
WHERE 5 > (SELECT MAX(x) FROM t)
另请参阅 MySQL 内部结构:MySQL 如何转换子查询。