ITEEDU

13.2.8.10. 优化子查询

开发过程不断进展,所以从长远来看,没有一个可靠的优化技巧。有些技巧您可能会感兴趣,并原意采用:

·         有些子句会影响在子查询中的行的数量和顺序。使用这类子句。例如:

·                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.8.11节,“把子查询作为用于早期MySQL版本的联合进行改写”

·         把子句从子查询的外部转移到内部。例如,使用此查询:

·                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);

·         Use NOT (a = ANY (...)) rather than a <> ALL (...).

·         Use x = ANY (table containing (1,2)) rather than x=1 OR x=2.

·         Use = ANY rather than 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工具,您可以了解到在您所处的情况下,哪些技巧会有帮助。

MySQL本身进行的部分优化包括:

·         MySQL只执行一次无关联子查询。使用EXPLAIN确认给定的子查询确实是无关联的。

·         MySQL改写IN, ALL, ANY和SOME子查询,目的是如果子查询中的select-list列已编制索引,则能发挥出此优势。

·         MySQL使用index-lookup函数代替以下格式的子查询。EXPLAIN把此函数描述为特殊的联合类型(unique_subquery或index_subquery):

·                ... IN (SELECT indexed_column FROM single_table ...)

·         当表达式中不包含NULL值或空集时,MySQL使用一个包含MIN()或MAX()的表达式,对以下格式的表达式进行扩展:

·                value {ALL|ANY|SOME} {> | < | >= | <=} (non-correlated subquery)

例如,本WHERE子句:

WHERE 5 > ALL (SELECT x FROM t)

可以用优化符进行如下处理:

WHERE 5 > (SELECT MAX(x) FROM t)

在MySQL内部手册中有一章名为“MySQL如何转换子查询”,可以从http://dev.mysql.com/doc/获取。