The optimizer can handle derived table references using two strategies (which also apply to view references and common table expressions):优化器可以使用两种策略(也适用于视图引用和公共表表达式)处理派生表引用:
Merge the derived table into the outer query block将派生表合并到外部查询块中
Materialize the derived table to an internal temporary table将派生表具体化为内部临时表
Example 1:例1:
SELECT * FROM (SELECT * FROM t1) AS derived_t1;
With merging of the derived table 合并派生表derived_t1
, that query is executed similar to:derived_t1
后,执行的查询类似于:
SELECT * FROM t1;
Example 2:例2:
SELECT * FROM t1 JOIN (SELECT t2.f1 FROM t2) AS derived_t2 ON t1.f2=derived_t2.f1 WHERE t1.f1 > 0;
With merging of the derived table 合并派生表derived_t2
, that query is executed similar to:derived_t2
后,执行的查询类似于:
SELECT t1.*, t2.f1 FROM t1 JOIN t2 ON t1.f2=t2.f1 WHERE t1.f1 > 0;
With materialization, 通过物化,derived_t1
and derived_t2
are each treated as a separate table within their respective queries.derived_t1
和derived_t2
在各自的查询中都被视为一个单独的表。
The optimizer handles derived tables, view references, and common table expressions the same way: It avoids unnecessary materialization whenever possible, which enables pushing down conditions from the outer query to derived tables and produces more efficient execution plans. 优化器以相同的方式处理派生表、视图引用和公共表表达式:它尽可能避免不必要的物化,从而可以将条件从外部查询下推到派生表,并生成更高效的执行计划。(For an example, see Section 8.2.2.2, “Optimizing Subqueries with Materialization”.)(例如,请参阅第8.2.2.2节,“使用物化优化子查询”。)
If merging would result in an outer query block that references more than 61 base tables, the optimizer chooses materialization instead.如果合并将导致引用超过61个基表的外部查询块,那么优化器将选择物化。
The optimizer propagates an 如果以下条件均为真,优化器将派生表或视图引用中的ORDER BY
clause in a derived table or view reference to the outer query block if these conditions are all true:ORDER BY
子句传播到外部查询块:
The outer query is not grouped or aggregated.外部查询未分组或聚合。
The outer query does not specify 外部查询未指定DISTINCT
, HAVING
, or ORDER BY
.DISTINCT
、HAVING
或ORDER BY
。
The outer query has this derived table or view reference as the only source in the 外部查询将此派生表或视图引用作为FROM
clause.FROM
子句中的唯一源。
Otherwise, the optimizer ignores the 否则,优化器将忽略ORDER BY
clause.ORDER BY
子句。
The following means are available to influence whether the optimizer attempts to merge derived tables, view references, and common table expressions into the outer query block:以下方法可用于影响优化器是否尝试将派生表、视图引用和公共表表达式合并到外部查询块中:
The 可以使用MERGE
and NO_MERGE
optimizer hints can be used. MERGE
和NO_MERGE
优化器提示。They apply assuming that no other rule prevents merging. 它们适用于假设没有其他规则阻止合并的情况。See Section 8.9.3, “Optimizer Hints”.请参阅第8.9.3节,“优化器提示”。
Similarly, you can use the 类似地,您可以使用derived_merge
flag of the optimizer_switch
system variable. optimizer_switch
系统变量的derived_merge
标志。See Section 8.9.2, “Switchable Optimizations”. 请参阅第8.9.2节“可切换优化”。By default, the flag is enabled to permit merging. 默认情况下,启用该标志以允许合并。Disabling the flag prevents merging and avoids 禁用该标志可防止合并并避免ER_UPDATE_TABLE_USED
errors.ER_UPDATE_TABLE_USED
错误。
The derived_merge
flag also applies to views that contain no ALGORITHM
clause. derived_merge
标志也适用于不包含算法子句的视图。Thus, if an 因此,如果使用与子查询等价的表达式的视图引用发生ER_UPDATE_TABLE_USED
error occurs for a view reference that uses an expression equivalent to the subquery, adding ALGORITHM=TEMPTABLE
to the view definition prevents merging and takes precedence over the derived_merge
value.ER_UPDATE_TABLE_USED
错误,则将ALGORITHM=TEMPTABLE
添加到视图定义会阻止合并,并优先于derived_merge
值。
It is possible to disable merging by using in the subquery any constructs that prevent merging, although these are not as explicit in their effect on materialization. 可以通过在子查询中使用任何阻止合并的构造来禁用合并,尽管这些构造对物化的影响不是那么明确。Constructs that prevent merging are the same for derived tables, common table expressions, and view references:对于派生表、公共表表达式和视图引用,阻止合并的构造是相同的:
Aggregate functions or window functions (聚合函数或窗口函数(SUM()
, MIN()
, MAX()
, COUNT()
, and so forth)SUM()
、MIN()
、MAX()
、COUNT()
等)
DISTINCT
GROUP BY
HAVING
LIMIT
Subqueries in the select list选择列表中的子查询
Assignments to user variables用户变量的赋值
Refererences only to literal values (in this case, there is no underlying table)仅引用文字值(在本例中,没有基础表)
If the optimizer chooses the materialization strategy rather than merging for a derived table, it handles the query as follows:如果优化器选择物化策略而不是合并派生表,它将按如下方式处理查询:
The optimizer postpones derived table materialization until its contents are needed during query execution. 优化器推迟派生表的具体化,直到查询执行期间需要它的内容。This improves performance because delaying materialization may result in not having to do it at all. 这会提高性能,因为延迟物化可能会导致根本不需要这样做。Consider a query that joins the result of a derived table to another table: If the optimizer processes that other table first and finds that it returns no rows, the join need not be carried out further and the optimizer can completely skip materializing the derived table.考虑将派生表的结果连接到另一个表的查询:如果优化器首先处理该另一个表并发现它没有返回行,则不需要进一步执行联接,而优化器可以完全跳过对派生表的实现。
During query execution, the optimizer may add an index to a derived table to speed up row retrieval from it.在查询执行期间,优化器可以向派生表添加索引,以加快从派生表中检索行的速度。
Consider the following 对于包含派生表的EXPLAIN
statement, for a SELECT
query that contains a derived table:SELECT
查询,请考虑下面的EXPLAIN
语句:
EXPLAIN SELECT * FROM (SELECT * FROM t1) AS derived_t1;
The optimizer avoids materializing the derived table by delaying it until the result is needed during 优化器通过将派生表延迟到SELECT
execution. SELECT
执行过程中需要结果时,从而避免具体化派生表。In this case, the query is not executed (because it occurs in an 在这种情况下,查询不会执行(因为它发生在EXPLAIN
statement), so the result is never needed.EXPLAIN
语句中),因此永远不需要结果。
Even for queries that are executed, delay of derived table materialization may enable the optimizer to avoid materialization entirely. 即使对于已执行的查询,派生表物化的延迟也可能使优化器完全避免物化。When this happens, query execution is quicker by the time needed to perform materialization. 当这种情况发生时,查询执行会比执行物化所需的时间更快。Consider the following query, which joins the result of a derived table to another table:考虑下面的查询,它将派生表的结果与另一个表连接:
SELECT * FROM t1 JOIN (SELECT t2.f1 FROM t2) AS derived_t2 ON t1.f2=derived_t2.f1 WHERE t1.f1 > 0;
If the optimization processes 如果优化首先处理t1
first and the WHERE
clause produces an empty result, the join must necessarily be empty and the derived table need not be materialized.t1
,并且WHERE
子句生成一个空结果,那么连接必须是空的,并且派生表不需要具体化。
For cases when a derived table requires materialization, the optimizer may add an index to the materialized table to speed up access to it. 对于派生表需要物化的情况,优化器可以向物化表添加索引以加快对它的访问。If such an index enables 如果这样的索引允许ref
access to the table, it can greatly reduce amount of data read during query execution. ref
访问表,则可以大大减少查询执行期间读取的数据量。Consider the following query:考虑下面的查询:
SELECT * FROM t1 JOIN (SELECT DISTINCT f1 FROM t2) AS derived_t2 ON t1.f1=derived_t2.f1;
The optimizer constructs an index over column 如果这样做将允许对最低成本的执行计划使用f1
from derived_t2
if doing so would enable use of ref
access for the lowest cost execution plan. ref
访问,那么优化器将在derived_t2
的f1
列上构造一个索引。After adding the index, the optimizer can treat the materialized derived table the same as a regular table with an index, and it benefits similarly from the generated index. 添加索引后,优化器可以将物化的派生表视为具有索引的常规表,并从生成的索引中获得类似的好处。The overhead of index creation is negligible compared to the cost of query execution without the index. 与没有索引的查询执行成本相比,创建索引的开销可以忽略不计。If 如果ref
access would result in higher cost than some other access method, the optimizer creates no index and loses nothing.ref
访问会导致比其他访问方法更高的成本,那么优化器不会创建索引,也不会丢失任何内容。
For optimizer trace output, a merged derived table or view reference is not shown as a node. 对于优化器跟踪输出,合并的派生表或视图引用不显示为节点。Only its underlying tables appear in the top query's plan.顶部查询的计划中仅显示其基础表。
What is true for materialization of derived tables is also true for common table expressions (CTEs). 对于派生表的物化是正确的,对于公共表表达式(CTE)也是正确的。In addition, the following considerations pertain specifically to CTEs.此外,以下注意事项特别适用于CTE。
If a CTE is materialized by a query, it is materialized once for the query, even if the query references it several times.如果一个CTE由一个查询具体化,那么即使查询多次引用它,它也会为该查询具体化一次。
A recursive CTE is always materialized.递归CTE总是具体化的。
If a CTE is materialized, the optimizer automatically adds relevant indexes if it estimates that indexing can speed up access by the top-level statement to the CTE. 如果CTE被物化,那么如果优化器估计索引可以加快顶级语句对CTE的访问,那么它会自动添加相关索引。This is similar to automatic indexing of derived tables, except that if the CTE is referenced multiple times, the optimizer may create multiple indexes, to speed up access by each reference in the most appropriate way.这类似于派生表的自动索引,只是如果CTE被多次引用,优化器可能会创建多个索引,以最适当的方式加速每个引用的访问。
The MERGE
and NO_MERGE
optimizer hints can be applied to CTEs. MERGE
优化器和NO_MERGE
优化器提示可应用于CTE。Each CTE reference in the top-level statement can have its own hint, permitting CTE references to be selectively merged or materialized. 顶级语句中的每个CTE引用都可以有自己的提示,允许有选择地合并或具体化CTE引用。The following statement uses hints to indicate that 下面的语句使用提示指示cte1
should be merged and cte2
should be materialized:cte1
应该合并、cte2
应该具体化:
WITH cte1 AS (SELECT a, b FROM table1), cte2 AS (SELECT c, d FROM table2) SELECT /*+ MERGE(cte1) NO_MERGE(cte2) */ cte1.b, cte2.d FROM cte1 JOIN cte2 WHERE cte1.a = cte2.c;
The ALGORITHM
clause for CREATE VIEW
does not affect materialization for any WITH
clause preceding the SELECT
statement in the view definition. CREATE VIEW
的ALGORITHM
子句不影响视图定义中SELECT
语句前面的WITH
子句的具体化。Consider this statement:考虑一下这个说法:
CREATE ALGORITHM={TEMPTABLE|MERGE} VIEW v1 AS WITH ... SELECT ...
The ALGORITHM
value affects materialization only of the SELECT
, not the WITH
clause.ALGORITHM
值仅影响SELECT
的具体化,而不影响WITH
子句。
Prior to MySQL 8.0.16, if 在MySQL 8.0.16之前,如果internal_tmp_disk_storage_engine=MYISAM
, an error occurred for any attempt to materialize a CTE using an on-disk temporary table, since for CTEs, the storage engine used for on-disk internal temporary tables could not be MyISAM
. internal_tmp_disk_storage_engine=MYISAM
,则任何使用磁盘上临时表具体化CTE的尝试都会发生错误,因为对于CTE,用于磁盘上内部临时表的存储引擎不能是MYISAM
。Beginning with MySQL 8.0.16, this is no longer an issue, since 从MySQL 8.0.16开始,这不再是一个问题,因为TempTable
now always uses InnoDB
for on-disk internal temporary tables.TempTable
现在总是使用InnoDB
作为磁盘上的内部临时表。
As mentioned previously, a CTE, if materialized, is materialized once, even if referenced multiple times. 如前所述,CTE如果被物化,则被物化一次,即使被多次引用。To indicate one-time materialization, optimizer trace output contains an occurrence of 为了指示一次性物化,优化器跟踪输出包含creating_tmp_table
plus one or more occurrences of reusing_tmp_table
.creating_tmp_table
的出现和reusing_tmp_table
的一次或多次出现。
CTEs are similar to derived tables, for which the CTE类似于派生表,其materialized_from_subquery
node follows the reference. materialized_from_subquery
节点遵循引用。This is true for a CTE that is referenced multiple times, so there is no duplication of 这对于多次引用的CTE是正确的,因此不存在materialized_from_subquery
nodes (which would give the impression that the subquery is executed multiple times, and produce unnecessarily verbose output). materialized_from_subquery
节点的复制(这会给人子查询执行多次的印象,并产生不必要的详细输出)。Only one reference to the CTE has a complete 只有一个对CTE的引用具有完整的materialized_from_subquery
node with the description of its subquery plan. materialized_from_subquery
节点及其子查询计划的描述。Other references have a reduced 其他引用具有一个减量的materialized_from_subquery
node. materialized_from_subquery
节点。The same idea applies to 同样的想法也适用于以EXPLAIN
output in TRADITIONAL
format: Subqueries for other references are not shown.TRADITIONAL
格式EXPLAIN
输出:不显示其他引用的子查询。