8.2.2.2 通过实现来优化子查询

优化器使用实现来启用更有效的子查询处理。物化通过生成子查询结果作为临时 table(通常在内存中)来加快查询执行速度。 MySQL 第一次需要子查询结果时,会将结果具体化为临时 table。任何随后的需要结果的时间,MySQL 都会再次引用临时 table。优化器可以使用哈希索引对 table 进行索引,以使查找快速,廉价。索引包含唯一值,以消除重复项并使 table 更小。

子查询实现在可能的情况下使用内存中的临时 table,如果 table 太大,则会退回到磁盘上的存储。参见第 8.4.4 节“ MySQL 中的内部临时 table 使用”

如果未使用实现,则优化器有时会将不相关的子查询重写为相关的子查询。例如,以下IN子查询是不相关的(* where_condition *仅涉及t2而不是t1的列):

SELECT * FROM t1
WHERE t1.a IN (SELECT t2.b FROM t2 WHERE where_condition);

优化器可能将此重写为EXISTS相关子查询:

SELECT * FROM t1
WHERE EXISTS (SELECT t2.b FROM t2 WHERE where_condition AND t1.a=t2.b);

使用临时 table 的子查询实现避免了这样的重写,并使得只可能执行一次子查询,而不是对外部查询的每一行执行一次。

为了使子查询实现在 MySQL 中使用,必须启用optimizer_switch系统变量materialization标志。 (请参见第 8.9.2 节“可切换的优化”。)启用materialization标志,实现适用于出现在以下任何一种情况下的谓词:在任何位置(在选择列 tableWHEREONGROUP BYHAVINGORDER BY中)出现的子查询谓词:

(oe_1, oe_2, ..., oe_N) [NOT] IN (SELECT ie_1, i_2, ..., ie_N ...)
oe [NOT] IN (SELECT ie ...)

以下示例说明了UNKNOWNFALSE谓词评估的等价要求如何影响是否可以使用子查询实现。假定* where_condition *仅包含来自t2而不是t1的列,因此子查询是不相关的。

此查询需要具体实现:

SELECT * FROM t1
WHERE t1.a IN (SELECT t2.b FROM t2 WHERE where_condition);

在这里,IN谓词返回UNKNOWNFALSE都没有关系。无论哪种方式,t1中的行都不会包含在查询结果中。

以下查询是不使用子查询实现的示例,其中t2.b是可为空的列:

SELECT * FROM t1
WHERE (t1.a,t1.b) NOT IN (SELECT t2.a,t2.b FROM t2
                          WHERE where_condition);

以下限制适用于子查询实现的使用:

在查询中使用EXPLAIN可以 table 明优化器是否使用子查询实现:

首页