#### 8.2.2.2 使用物化优化子查询

[](<>)[](<>)[](<>)

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

子查询实现尽可能使用内存中的临时表，如果表变得太大，则回退到磁盘存储。看[第 8.4.4 节，“MySQL 中的内部临时表使用”](internal-temporary-tables.html).

如果不使用具体化，优化器有时会将非相关子查询重写为相关子查询。例如，以下`在`子查询不相关（*`where_condition`*仅涉及来自的列`t2`并不是`t1`):

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

优化器可能会将其重写为`存在`相关子查询：

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

使用临时表的子查询实现避免了这种重写，并且可以只执行一次子查询，而不是每行外部查询执行一次。

对于要在 MySQL 中使用的子查询实现，[`优化器开关`](server-system-variables.html#sysvar_optimizer_switch)系统变量[`物化`](switchable-optimizations.html#optflag_materialization)标志必须启用。（看[第 8.9.2 节，“可切换的优化”](switchable-optimizations.html).) 随着[`物化`](switchable-optimizations.html#optflag_materialization)启用标志，具体化适用于出现在任何地方的子查询谓词（在选择列表中，`在哪里`,`在`,`通过...分组`,`拥有`， 要么`订购方式`)，对于属于以下任何用例的谓词：

-   谓词有这种形式，当没有外部表达式时*`oe_i`*或内心的表达*`ie_i`*可以为空。*`ñ`*为 1 或更大。

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

-   当只有一个外部表达式时，谓词具有这种形式*`oe`*和内心的表达*`ie`*.表达式可以为空。

    ```
    oe [NOT] IN (SELECT ie ...)
    ```

-   谓词是`在`要么`不在`和结果`未知`(`空值`) 具有相同的含义，因为`错误的`.

    以下示例说明了对等价的要求如何`未知`和`错误的`谓词评估影响是否可以使用子查询实现。假使，假设*`where_condition`*仅涉及来自的列`t2`并不是`t1`这样子查询是不相关的。

    此查询受具体化的影响：


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

在这里，无论是否`在`谓词返回`未知`要么`错误的`.无论哪种方式，从`t1`不包含在查询结果中。

不使用子查询具体化的示例是以下查询，其中`t2.b`是一个可为空的列：

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

以下限制适用于子查询具体化的使用：

-   内部和外部表达式的类型必须匹配。例如，如果两个表达式都是整数或都是十进制，优化器可能能够使用具体化，但如果一个表达式是整数而另一个表达式是十进制则不能。

-   内部表达式不能是[`斑点`](blob.html).

    用于[`解释`](explain.html)with 查询提供了优化器是否使用子查询实现的一些指示：

-   与不使用具体化的查询执行相比，`选择类型`可能会从`依赖子查询`到`子查询`.这表明，对于每外行执行一次的子查询，物化使子查询仅执行一次。

-   对于扩展[`解释`](explain.html)输出，由以下显示的文本[`显示警告`](show-warnings.html)包括`物化`和`物化子查询`.

    在 MySQL 8.0.21 及更高版本中，MySQL 还可以将子查询物化应用于单表[`更新`](update.html)要么[`删除`](delete.html)使用 a 的语句`[不] 在`要么`[不存在`子查询谓词，前提是语句不使用`订购方式`要么`限制`，并且优化器提示或[`优化器开关`](server-system-variables.html#sysvar_optimizer_switch)环境。
