8.2.2.2 Optimizing Subqueries with Materialization用物化方法优化子查询

The optimizer uses materialization to enable more efficient subquery processing. 优化器使用物化来实现更高效的子查询处理。Materialization speeds up query execution by generating a subquery result as a temporary table, normally in memory. 物化通过将子查询结果生成为临时表(通常在内存中)来加速查询执行。The first time MySQL needs the subquery result, it materializes that result into a temporary table. MySQL第一次需要子查询结果时,会将结果具体化为一个临时表。Any subsequent time the result is needed, MySQL refers again to the temporary table. 任何后续需要结果的时候,MySQL都会再次引用临时表。The optimizer may index the table with a hash index to make lookups fast and inexpensive. 优化器可以使用散列索引对表进行索引,以使查找快速且便宜。The index contains unique values to eliminate duplicates and make the table smaller.索引包含唯一的值以消除重复项并使表更小。

Subquery materialization uses an in-memory temporary table when possible, falling back to on-disk storage if the table becomes too large. 子查询具体化在可能的情况下使用内存中的临时表,如果表太大,则返回到磁盘上存储。See Section 8.4.4, “Internal Temporary Table Use in MySQL”.请参阅第8.4.4节,“MySQL中的内部临时表使用”

If materialization is not used, the optimizer sometimes rewrites a noncorrelated subquery as a correlated subquery. 如果不使用物化,优化器有时会将非相关子查询重写为相关子查询。For example, the following IN subquery is noncorrelated (where_condition involves only columns from t2 and not t1):例如,以下的IN子查询是不相关的(where_condition只涉及t2中的列,而不涉及t1中的列):

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

The optimizer might rewrite this as an EXISTS correlated subquery:优化器可能会将其重写为EXISTS相关的子查询:

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

Subquery materialization using a temporary table avoids such rewrites and makes it possible to execute the subquery only once rather than once per row of the outer query.使用临时表的子查询具体化避免了这种重写,并使子查询只能执行一次,而不是外部查询的每行执行一次。

For subquery materialization to be used in MySQL, the optimizer_switch system variable materialization flag must be enabled. 要在MySQL中使用子查询物化,必须启用optimizer_switch系统变量materialization标志。(See Section 8.9.2, “Switchable Optimizations”.) (请参阅第8.9.2节,“可切换的优化”。)With the materialization flag enabled, materialization applies to subquery predicates that appear anywhere (in the select list, WHERE, ON, GROUP BY, HAVING, or ORDER BY), for predicates that fall into any of these use cases:启用materialization标志后,物化应用于出现在任意位置(在选择列表、WHEREONGROUP BYHAVINGORDER BY中)的子查询谓词,这些谓词属于以下任何用例:

The following examples illustrate how the requirement for equivalence of UNKNOWN and FALSE predicate evaluation affects whether subquery materialization can be used. 下面的示例说明了对UNKNOWN谓词和FALSE谓词求值的等价性的要求如何影响子查询物化是否可以使用。Assume that where_condition involves columns only from t2 and not t1 so that the subquery is noncorrelated.假设where_condition只涉及t2中的列,而不涉及t1中的列,因此子查询是不相关的。

This query is subject to materialization:此查询需要具体化:

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

Here, it does not matter whether the IN predicate returns UNKNOWN or FALSE. 在这里,IN谓词返回UNKNOWN还是FALSE并不重要。Either way, the row from t1 is not included in the query result.无论哪种方式,t1中的行都不包括在查询结果中。

An example where subquery materialization is not used is the following query, where t2.b is a nullable column:未使用子查询具体化的一个示例是以下查询,其中t2.b是可为空的列:

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

The following restrictions apply to the use of subquery materialization:以下限制适用于子查询具体化的使用:

Use of EXPLAIN with a query provides some indication of whether the optimizer uses subquery materialization:在查询中使用EXPLAIN可以指示优化器是否使用子查询具体化:

In MySQL 8.0.21 and later, MySQL can also apply subquery materialization to a single-table UPDATE or DELETE statement that uses a [NOT] IN or [NOT] EXISTS subquery predicate, provided that the statement does not use ORDER BY or LIMIT, and that subquery materialization is allowed by an optimizer hint or by the optimizer_switch setting.在MySQL 8.0.21及更高版本中,MySQL还可以对使用[NOT] IN[NOT] EXISTS子查询谓词的单个表UPDATE语句或DELETE语句应用子查询物化,前提是该语句不使用ORDER BYLIMIT,并且优化器提示或optimizer_switch设置允许子查询物化。