文档首页
MySQL 9.0 参考手册
相关文档 下载本手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


10.2.2.2 使用物化优化子查询

优化器使用物化来实现更有效的子查询处理。物化通过生成子查询结果作为临时表(通常在内存中)来加快查询执行速度。第一次 MySQL 需要子查询结果时,它会将该结果物化到一个临时表中。之后每次需要该结果时,MySQL 都会再次引用该临时表。优化器可能会使用哈希索引对该表进行索引,以使查找速度快且成本低。索引包含唯一值以消除重复并使表更小。

子查询物化在可能的情况下使用内存中的临时表,如果表变得太大,则回退到磁盘存储。请参阅第 10.4.4 节,“MySQL 中的内部临时表使用”

如果没有使用物化,优化器有时会将非相关子查询重写为相关子查询。例如,以下 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);

使用临时表进行子查询物化避免了这种重写,并使子查询仅执行一次而不是每次执行外层查询的行都执行一次成为可能。

为了使子查询物化在 MySQL 中使用,optimizer_switch 系统变量的 materialization 标志必须启用。(请参阅第 10.9.2 节,“可切换优化”。)在启用 materialization 标志后,物化将应用于出现在任何地方(在 select 列表、WHEREONGROUP BYHAVINGORDER BY 中)的子查询谓词,以及属于以下任何用例的谓词

  • 当没有外层表达式 oe_i 或内层表达式 ie_i 是可为空时,谓词具有以下形式。N 为 1 或更大。

    (oe_1, oe_2, ..., oe_N) [NOT] IN (SELECT ie_1, i_2, ..., ie_N ...)
  • 当存在单个外层表达式 oe 和内层表达式 ie 时,谓词具有以下形式。表达式可以是可为空的。

    oe [NOT] IN (SELECT ie ...)
  • 谓词为 INNOT INUNKNOWN (NULL) 的结果与 FALSE 的结果具有相同的含义。

以下示例说明了 UNKNOWNFALSE 谓词评估的等效性要求如何影响是否可以使用子查询物化。假设 where_condition 仅涉及 t2 中的列,而不是 t1 中的列,以便子查询是非相关的。

此查询可以使用物化

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

这里,IN 谓词返回 UNKNOWN 还是 FALSE 并不重要。无论哪种方式,t1 中的行都不会包含在查询结果中。

以下查询是子查询物化未使用的示例,其中 t2.b 是可为空的列

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

使用子查询物化有以下限制

  • 内层表达式和外层表达式的类型必须匹配。例如,如果两个表达式都是整数或都是十进制数,优化器可能可以使用物化,但如果一个表达式是整数,另一个表达式是十进制数,则不能使用物化。

  • 内层表达式不能是 BLOB

使用带有查询的 EXPLAIN 提供了优化器是否使用子查询物化的一些指示

  • 与不使用物化的查询执行相比,select_type 可能从 DEPENDENT SUBQUERY 更改为 SUBQUERY。这表明,对于一个原本会为每个外部行执行一次的子查询,物化使子查询仅执行一次成为可能。

  • 对于扩展的 EXPLAIN 输出,以下 SHOW WARNINGS 显示的文本包含 materializematerialized-subquery

MySQL 还可以将子查询物化应用于使用 [NOT] IN[NOT] EXISTS 子查询谓词的单表 UPDATEDELETE 语句,前提是该语句不使用 ORDER BYLIMIT,并且子查询物化被优化器提示或 optimizer_switch 设置允许。