MySQL 8.0.22 及更高版本支持符合条件的子查询的派生条件下推。对于诸如 之类的查询,在许多情况下可以将外部
条件下推到派生表,在这种情况下会导致
. 当派生表无法合并到外层查询时(例如,如果派生表使用聚合),将外部条件下推到派生表应该减少需要处理的行数,从而加快执行速度询问。
SELECT *
FROM (SELECT i, j FROM t1) AS dt WHERE i >
constant
WHERE
SELECT * FROM (SELECT i, j FROM t1 WHERE i >
constant
) AS dtWHERE
在 MySQL 8.0.22 之前,如果派生表被具体化但未合并,MySQL 会具体化整个表,然后使用条件限定所有结果行
WHERE
。如果未启用派生条件下推,或者由于某些其他原因无法使用,情况仍然如此。
在以下情况下,可以将外部WHERE
条件下推到派生物化表:
当派生表不使用聚合或窗口函数时,
WHERE
可以直接将外部条件下推给它。这包括WHERE
具有多个谓词与AND
、OR
或两者连接的条件。例如,查询
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
.当派生表具有 a并且不使用窗口函数时,引用一个或多个不属于的列
GROUP BY
的外部 条件可以作为条件下推到派生表 。WHERE
GROUP BY
HAVING
例如,
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
。当派生表使用 a
GROUP BY
并且外部WHERE
条件中的列是GROUP BY
列时,WHERE
引用这些列的条件可以直接下推到派生表。例如,查询
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
.如果外部
WHERE
条件有谓词引用列的一部分,也有谓词引用不属于的GROUP BY
列,则前一类谓词作为WHERE
条件下推,而后一类谓词作为条件下推HAVING
。例如,在查询中,外部 子句 中SELECT * FROM (SELECT i, j, SUM(k) AS sum FROM t1 GROUP BY i,j) AS dt WHERE i > 10 AND sum > 100
的谓词引用了一个列,而谓词 不引用任何i > 10
WHERE
GROUP BY
sum > 100
GROUP BY
柱子。因此,派生表下推优化导致查询以类似于此处显示的方式重写:SELECT * FROM ( SELECT i, j, SUM(k) AS sum FROM t1 WHERE i > 10 GROUP BY i, j HAVING sum > 100 ) AS dt;
要启用派生条件下推,
optimizer_switch
系统变量的
derived_condition_pushdown
标志(在此版本中添加)必须设置为
on
,这是默认设置。如果此优化被 禁用
,您可以使用
优化器提示optimizer_switch
为特定查询启用它
。DERIVED_CONDITION_PUSHDOWN
要禁用给定查询的优化,请使用
NO_DERIVED_CONDITION_PUSHDOWN
优化器提示。
以下约束和限制适用于派生表条件下推优化:
如果派生表包含 ,则无法使用优化
UNION
。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
查询顶层中存在的条件SELECT * FROM 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 及更高版本中,派生表条件下推优化可以与
UNION
查询一起使用,但以下情况除外:UNION
如果属于递归公用表表达式的任何具体化派生表是UNION
递归公用表表达式(请参阅 递归公用表表达式) ,则 条件下推不能与查询一起使用 。包含不确定表达式的条件不能下推到派生表。
派生表不能使用
LIMIT
子句。不能下推包含子查询的条件。
如果派生表是外连接的内表,则不能使用优化。
如果物化派生表是公用表表达式,则如果它被多次引用,则条件不会下推到它。
如果条件的形式为 ,则可以下推使用参数的条件
。如果外部derived_column
> ?WHERE
条件中的派生列是在基础派生表中具有 a 的表达式,?
则无法下推该条件。对于条件在使用
ALGORITHM=TEMPTABLE
而不是视图本身创建的视图的表上的查询,在解析时不识别多重相等性,因此不能不下推条件。这是因为,在优化查询时,条件下推发生在解析阶段,而多重相等性传播发生在优化期间。在这种情况下,对于使用 的视图来说,这不是问题
ALGORITHM=MERGE
,因为可以传播相等性并下推条件。SELECT
从 MySQL 8.0.28 开始,如果派生表的列表包含对用户变量的任何分配, 则无法下推条件。(漏洞 #104918)