#### 8.2.2.5 衍生条件下推优化

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

MySQL 8.0.22 及更高版本支持符合条件的子查询的派生条件下推。对于查询，例如`SELECT * FROM (SELECT i, j FROM t1) AS dt WHERE i > *`持续的`*`, 在很多情况下可以推外`在哪里`条件到派生表，在这种情况下导致`SELECT * FROM (SELECT i, j FROM t1 WHERE i > *`持续的`*) 作为 dt`.当派生表无法合并到外层查询时（例如派生表使用聚合），推送外层查询`在哪里`派生表的条件应该会减少需要处理的行数，从而加快查询的执行速度。

笔记

在 MySQL 8.0.22 之前，如果派生表已物化但未合并，则 MySQL 会物化整个表，然后使用`在哪里`健康）状况。如果派生条件下推未启用，或者由于某些其他原因无法使用，情况仍然如此。

外`在哪里`在以下情况下，可以将条件下推到派生的物化表：

-   当派生表不使用聚合或窗口函数时，外部表`在哪里`条件可以直接下推到它上面。这包括`在哪里`有多个谓词连接的条件`和`,`要么`， 或两者。

    例如，查询`SELECT * FROM (SELECT f1, f2 FROM t1) AS dt WHERE f1 < 3 AND f2 > 11`被改写为`SELECT f1, f2 FROM (SELECT f1, f2 FROM t1 WHERE f1 < 3 AND f2 > 11) AS dt`.

-   当派生表有一个`通过...分组`并且不使用窗口函数，外部`在哪里`条件引用一个或多个不属于`通过...分组`可以下推到派生表作为`拥有`健康）状况。

    例如，`SELECT * FROM (SELECT i, j, SUM(k) AS sum FROM t1 GROUP BY i, j) AS dt WHERE sum > 100`在派生条件下推后重写为`SELECT * FROM (SELECT i, j, SUM(k) AS sum FROM t1 GROUP BY i, j HAVING sum > 100) AS dt`.

-   当派生表使用`通过...分组`和外部的列`在哪里`条件是`通过...分组`列`在哪里`引用这些列的条件可以直接下推到派生表。

    例如，查询`SELECT * FROM (SELECT i,j, SUM(k) AS sum FROM t1 GROUP BY i,j) AS dt WHERE i > 10`被改写为`SELECT * FROM (SELECT i,j, SUM(k) AS sum FROM t1 WHERE i > 10 GROUP BY i,j) AS dt`.

    如果外部`在哪里`条件具有引用列的谓词，这些列是`通过...分组`以及引用非列的谓词，前一种类型的谓词被下推为`在哪里`条件，而后一种类型的被推下为`拥有`状况。例如，在查询`SELECT * FROM (SELECT i, j, SUM(k) AS sum FROM t1 GROUP BY i,j) AS dt WHERE i > 10 AND sum > 100`, 谓词`我 > 10`在外`在哪里`子句引用 a`通过...分组`列，而谓词`总和 > 100`不参考任何`通过...分组`柱子。因此，派生表下推优化导致查询以类似于此处所示的方式重写：

    ```
    SELECT * FROM (
        SELECT i, j, SUM(k) AS sum FROM t1
            WHERE i > 10
            GROUP BY i, j
            HAVING sum > 100
        ) AS dt;
    ```

    为了启用派生条件下推，[`优化器开关`](server-system-variables.html#sysvar_optimizer_switch)系统变量[`派生条件下推`](switchable-optimizations.html#optflag_derived-condition-pushdown)标志（在此版本中添加）必须设置为`在`，这是默认设置。如果此优化被禁用`优化器开关`，您可以使用[`DERIVED_CONDITION_PUSHDOWN`](optimizer-hints.html#optimizer-hints-table-level)优化器提示。要禁用给定查询的优化，请使用[`NO_DERIVED_CONDITION_PUSHDOWN`](optimizer-hints.html#optimizer-hints-table-level)优化器提示。

    以下限制和限制适用于派生表条件下推优化：

-   如果派生表包含，则无法使用优化[`联盟`](union.html).MySQL 8.0.29 中取消了此限制。考虑两张表`t1`和`t2`, 和一个视图`v`包含他们的联合，创建如下所示：

    ```
    CREATE TABLE t1 (
      id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
      c1 INT,
      KEY i1 (c1)
    );

    CREATE TABLE t2 (
      id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
      c1 INT,
      KEY i1 (c1)
    );

    CREATE OR REPLACE VIEW v AS
         SELECT id, c1 FROM t1
         UNION ALL
         SELECT id, c1 FROM t2;
    ```

    从输出中可以看出[`解释`](explain.html#explain-execution-plan), 查询顶层中存在的条件，例如`选择 * 从 v WHERE c1 = 12`现在可以下推到派生表中的两个查询块：

    ```
    mysql> EXPLAIN FORMAT=TREE SELECT * FROM v WHERE c1 = 12\G
    *************************** 1. row ***************************
    EXPLAIN: -> Table scan on v  (cost=1.26..2.52 rows=2)
        -> Union materialize  (cost=2.16..3.42 rows=2)
            -> Covering index lookup on t1 using i1 (c1=12)  (cost=0.35 rows=1)
            -> Covering index lookup on t2 using i1 (c1=12)  (cost=0.35 rows=1)

    1 row in set (0.00 sec)
    ```

    在 MySQL 8.0.29 及更高版本中，派生表条件下推优化可以与`联盟`查询，但以下情况除外：

    -   条件下推不能与`联盟`查询是否有任何物化派生表属于`联盟`是一个递归公用表表达式（参见[递归公用表表达式](with.html#common-table-expressions-recursive)）。

    -   不能将包含不确定表达式的条件下推到派生表中。

-   派生表不能使用`限制`条款。

-   包含子查询的条件不能下推。

-   如果派生表是外连接的内表，则不能使用优化。

-   如果具体化派生表是公用表表达式，则如果多次引用它，则不会将条件下推到它。

-   使用参数的条件如果条件是形式可以下推`*`派生列`* > ?`.如果外部的派生列`在哪里`条件是具有`?`在基础派生表中，此条件无法下推。

-   从 MySQL 8.0.28 开始，如果派生表的`选择`列表包含对用户变量的任何分配。（错误 #104918）
