8.4 中文镜像

MySQL 8.4 参考手册 · 中文镜像

正文为中文,英文原文默认隐藏。点击任意中文段落即可展开 / 收起对应英文原文。

打开官方英文原文 ↗

译文由机器翻译生成,仅供理解参考;有疑问请以官方英文原文为准。

中文点击中文段落可显示 / 隐藏英文原文本页译文覆盖 100%

10.9.2 可切换优化10.9.2 Switchable Optimizations

optimizer_switch 系统变量用于控制优化器行为。它的值是一组标志,每个标志的值可以是 on 或 off,以指示相应的优化器行为是启用还是禁用。该变量具有全局值和会话值,并且可以在运行时更改。全局默认值可以在服务器启动时设置。The optimizer_switch system variable enables control over optimizer behavior. Its value is a set of flags, each of which has a value of on or off to indicate whether the corresponding optimizer behavior is enabled or disabled. This variable has global and session values and can be changed at runtime. The global default can be set at server startup.

要查看当前的优化器标志集,请选择变量值:To see the current set of optimizer flags, select the variable value:

mysql> SELECT @@optimizer_switch\G
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,
                    index_merge_sort_union=on,index_merge_intersection=on,
                    engine_condition_pushdown=on,index_condition_pushdown=on,
                    mrr=on,mrr_cost_based=on,block_nested_loop=on,
                    batched_key_access=off,materialization=on,semijoin=on,
                    loosescan=on,firstmatch=on,duplicateweedout=on,
                    subquery_materialization_cost_based=on,
                    use_index_extensions=on,condition_fanout_filter=on,
                    derived_merge=on,use_invisible_indexes=off,skip_scan=on,
                    hash_join=on,subquery_to_derived=off,
                    prefer_ordering_index=on,hypergraph_optimizer=off,
                    derived_condition_pushdown=on,hash_set_operations=on
1 row in set (0.00 sec)

要更改 optimizer_switch 的值,请分配一个由一个或多个命令组成的逗号分隔的值:To change the value of optimizer_switch, assign a value consisting of a comma-separated list of one or more commands:

SET [GLOBAL|SESSION] optimizer_switch='command[,command]...';

每个 command 值应具有下表所示的形式之一。Each command value should have one of the forms shown in the following table.

命令语法Command Syntax 意义Meaning
defaultdefault 将每个优化重置为默认值Reset every optimization to its default value
opt_name=defaultopt_name=default 将指定的优化设置为其默认值Set the named optimization to its default value
opt_name=offopt_name=off 禁用指定的优化Disable the named optimization
opt_name=onopt_name=on 启用指定的优化Enable the named optimization

值中命令的顺序无关紧要,但如果存在,default 命令会首先执行。将 opt_name 标志设置为 default 会将其设置为 on 或 off 中的默认值。值中不允许重复指定任何给定的 opt_name,否则会导致错误。值中出现的任何错误都会导致赋值失败,并出现错误,同时保持 optimizer_switch 的值不变。The order of the commands in the value does not matter, although the default command is executed first if present. Setting an opt_name flag to default sets it to whichever of on or off is its default value. Specifying any given opt_name more than once in the value is not permitted and causes an error. Any errors in the value cause the assignment to fail with an error, leaving the value of optimizer_switch unchanged.

下面的列表描述了允许的 opt_name 标志名称,按优化策略分组:The following list describes the permissible opt_name flag names, grouped by optimization strategy:

  • 批量密钥访问标志Batched Key Access Flags

    要使 batched_key_access 在设置为 on 时生效,mrr 标志也必须设置为 on。目前,MRR 的成本估算过于悲观。因此,为了使用 BKA,mrr_cost_based 也必须设置为 off。For batched_key_access to have any effect when set to on, the mrr flag must also be on. Currently, the cost estimation for MRR is too pessimistic. Hence, it is also necessary for mrr_cost_based to be off for BKA to be used.

    欲了解更多信息,请参见 第 10.2.1.12 节,“块嵌套循环和批量键访问连接”。For more information, see Section 10.2.1.12, “Block Nested-Loop and Batched Key Access Joins”.

  • 块嵌套循环标志Block Nested-Loop Flags

    欲了解更多信息,请参见 第 10.2.1.12 节,“块嵌套循环和批量键访问连接”。For more information, see Section 10.2.1.12, “Block Nested-Loop and Batched Key Access Joins”.

  • 条件过滤标志Condition Filtering Flags

    欲了解更多信息,请参见 第 10.2.1.13 节,“条件过滤”。For more information, see Section 10.2.1.13, “Condition Filtering”.

  • 派生条件下推标志Derived Condition Pushdown Flags

    欲了解更多信息,请参见 第 10.2.2.5 节,“派生条件下推优化”For more information, see Section 10.2.2.5, “Derived Condition Pushdown Optimization”

  • 派生表合并标志Derived Table Merging Flags

    • derived_merge(默认 on) derived_merge (default on)

      控制派生表和视图合并到外部查询块中。Controls merging of derived tables and views into outer query block.

    derived_merge 标志控制优化器是否尝试将派生表、视图引用和公共表表达式合并到外部查询块中,前提是没有其他规则阻止合并;例如,视图的 ALGORITHM 指令优先于 derived_merge 设置。默认情况下,该标志为 on 以启用合并。The derived_merge flag controls whether the optimizer attempts to merge derived tables, view references, and common table expressions into the outer query block, assuming that no other rule prevents merging; for example, an ALGORITHM directive for a view takes precedence over the derived_merge setting. By default, the flag is on to enable merging.

    欲了解更多信息,请参见 第 10.2.2.4 节,“通过合并或物化优化派生表、视图引用和公共表表达式”。For more information, see Section 10.2.2.4, “Optimizing Derived Tables, View References, and Common Table Expressions with Merging or Materialization”.

  • 引擎状态下推标志Engine Condition Pushdown Flags

    欲了解更多信息,请参见第 10.2.1.5 节,“引擎条件下推优化”。For more information, see Section 10.2.1.5, “Engine Condition Pushdown Optimization”.

  • 哈希连接标志Hash Join Flags

    更多信息,请参见 第 10.2.1.4 节,“哈希连接优化”。For more information, see Section 10.2.1.4, “Hash Join Optimization”.

  • 索引条件下推标志Index Condition Pushdown Flags

    欲了解更多信息,请参见 第 10.2.1.6 节,“索引条件下推优化”。For more information, see Section 10.2.1.6, “Index Condition Pushdown Optimization”.

  • 索引 扩展 标志Index Extensions Flags

    欲了解更多信息,请参见 第 10.3.10 节,“使用索引扩展”。For more information, see Section 10.3.10, “Use of Index Extensions”.

  • 索引合并标志Index Merge Flags

    更多信息,请参见第 10.2.1.3 节,“索引合并优化”。For more information, see Section 10.2.1.3, “Index Merge Optimization”.

  • 索引可见性标志Index Visibility Flags

    欲了解更多信息,请参见 第 10.3.12 节,“隐形索引”。For more information, see Section 10.3.12, “Invisible Indexes”.

  • 限制优化标志Limit Optimization Flags

    • prefer_ordering_index(默认 on) prefer_ordering_index (default on)

      控制在查询包含 ORDER BY 或 GROUP BY 并带有 LIMIT 子句的情况下,优化器是否尝试使用有序索引,而不是无序索引、文件排序或其他优化。每当优化器判断使用该优化可以加快查询执行时,将默认执行此优化。Controls whether, in the case of a query having an ORDER BY or GROUP BY with a LIMIT clause, the optimizer tries to use an ordered index instead of an unordered index, a filesort, or some other optimization. This optimization is performed by default whenever the optimizer determines that using it would allow for faster execution of the query.

      由于用于做出此决定的算法无法处理所有可能的情况(部分原因是其假设数据的分布总是或多或少均匀的),因此在某些情况下,这种优化可能并不理想。可以通过将 prefer_ordering_index 标志设置为 off 来禁用此优化。Because the algorithm that makes this determination cannot handle every conceivable case (due in part to the assumption that the distribution of data is always more or less uniform), there are cases in which this optimization may not be desirable. This optimization can be disabled by setting the prefer_ordering_index flag to off.

    有关更多信息和示例,请参见 第 10.2.1.19 节,“LIMIT 查询优化”。For more information and examples, see Section 10.2.1.19, “LIMIT Query Optimization”.

  • 多范围读取标志Multi-Range Read Flags

    • mrr(默认 on) mrr (default on)

      控制多范围读取策略。Controls the Multi-Range Read strategy.

    • mrr_cost_based(默认 on) mrr_cost_based (default on)

      如果 mrr=on,则控制基于成本的 MRR 使用。Controls use of cost-based MRR if mrr=on.

    更多信息,请参见 第 10.2.1.11 节,“多范围读取优化”。For more information, see Section 10.2.1.11, “Multi-Range Read Optimization”.

  • 半连接标志Semijoin Flags

    • duplicateweedout(默认 on) duplicateweedout (default on)

      控制半连接重复消除策略。Controls the semijoin Duplicate Weedout strategy.

    • firstmatch(默认 on) firstmatch (default on)

      控制半连接的首匹配策略。Controls the semijoin FirstMatch strategy.

    • loosescan (默认 on) loosescan (default on)

      控制半连接 LooseScan 策略(不要与用于 GROUP BY 的松散索引扫描混淆)。Controls the semijoin LooseScan strategy (not to be confused with Loose Index Scan for GROUP BY).

    • semijoin (默认 on) semijoin (default on)

      控制所有半连接策略。Controls all semijoin strategies.

      这也适用于反连接优化。This also applies to the antijoin optimization.

    semijoin、firstmatch、loosescan 和 duplicateweedout 标志可以控制半连接策略。semijoin 标志控制是否使用半连接。如果将其设置为 on,则 firstmatch 和 loosescan 标志将允许对允许的半连接策略进行更精细的控制。The semijoin, firstmatch, loosescan, and duplicateweedout flags enable control over semijoin strategies. The semijoin flag controls whether semijoins are used. If it is set to on, the firstmatch and loosescan flags enable finer control over the permitted semijoin strategies.

    如果duplicateweedout 半连接策略被禁用,除非所有其他适用策略也被禁用,否则不会使用它。If the duplicateweedout semijoin strategy is disabled, it is not used unless all other applicable strategies are also disabled.

    如果semijoin 和 materialization 都为 on,半连接在适用时也会使用物化。这些标志默认是 on。If semijoin and materialization are both on, semijoins also use materialization where applicable. These flags are on by default.

    更多信息,请参见 使用半连接转换优化 IN 和 EXISTS 子查询谓词。For more information, see Optimizing IN and EXISTS Subquery Predicates with Semijoin Transformations.

  • 设置操作标志Set Operations Flags

    • hash_set_operations(默认 on) hash_set_operations (default on)

      启用针对涉及 EXCEPT 和 INTERSECT 的集合操作的哈希表优化;默认启用。否则,将使用基于临时表的去重方法,如 MySQL 之前的版本中所使用。Enables the hash table optimization for set operations involving EXCEPT and INTERSECT); enabled by default. Otherwise, temporary table based de-duplication is used, as in previous versions of MySQL.

      此优化使用的哈希内存量可以通过 set_operations_buffer_size 系统变量进行控制;通常增加此值会使使用这些操作的语句执行时间更短。The amount of memory used for hashing by this optimization can be controlled using the set_operations_buffer_size system variable; increasing this generally results in faster execution times for statements using these operations.

  • 跳过扫描标志Skip Scan Flags

    • skip_scan(默认 on) skip_scan (default on)

      控制跳过扫描访问方法的使用。Controls use of Skip Scan access method.

    更多信息,请参见 跳跃扫描范围访问方法。For more information, see Skip Scan Range Access Method.

  • 子查询物化标志Subquery Materialization Flags

    materialization 标志控制是否使用子查询物化。如果 semijoin 和 materialization 都是 on 的,半连接在适用时也使用物化。这些标志默认都是 on 的。The materialization flag controls whether subquery materialization is used. If semijoin and materialization are both on, semijoins also use materialization where applicable. These flags are on by default.

    subquery_materialization_cost_based 标志允许控制在子查询物化和 IN-到-EXISTS 子查询转换之间的选择。如果该标志为 on(默认值),优化器将在可以使用任一方法的情况下,基于成本在子查询物化和 IN-到-EXISTS 子查询转换之间进行选择。如果该标志为 off,优化器会选择子查询物化而不是 IN-到-EXISTS 子查询转换。The subquery_materialization_cost_based flag enables control over the choice between subquery materialization and IN-to-EXISTS subquery transformation. If the flag is on (the default), the optimizer performs a cost-based choice between subquery materialization and IN-to-EXISTS subquery transformation if either method could be used. If the flag is off, the optimizer chooses subquery materialization over IN-to-EXISTS subquery transformation.

    更多信息,请参见 第 10.2.2 节,“优化子查询、派生表、视图引用和公共表表达式”。For more information, see Section 10.2.2, “Optimizing Subqueries, Derived Tables, View References, and Common Table Expressions”.

  • 子查询转换标志Subquery Transformation Flags

    • subquery_to_derived(默认 off) subquery_to_derived (default off)

      优化器在许多情况下能够将 SELECT、WHERE、JOIN 或 HAVING 子句中的标量子查询转换为衍生表的左外连接。(根据衍生表的可空性,这有时可以进一步简化为内连接。)这可以用于满足以下条件的子查询:The optimizer is able in many cases to transform a scalar subquery in a SELECT, WHERE, JOIN, or HAVING clause into a left outer join on a derived table. (Depending on the nullability of the derived table, this can sometimes be simplified further to an inner join.) This can be done for a subquery which meets the following conditions:

      • 子查询不使用任何非确定性函数,例如 RAND()。The subquery does not make use of any nondeterministic functions, such as RAND().

      • 子查询不是可以重写为使用 MIN() 或 MAX() 的 ANY 或 ALL 子查询。The subquery is not an ANY or ALL subquery which can be rewritten to use MIN() or MAX().

      • 父查询不会设置用户变量,因为重写它可能会影响执行顺序,如果在同一查询中多次访问该变量,可能会导致意外结果。The parent query does not set a user variable, since rewriting it may affect the order of execution, which could lead to unexpected results if the variable is accessed more than once in the same query.

      • 子查询不应是相关查询,也就是说,它不应引用外部查询中表的列,或包含在外部查询中计算的聚合函数。The subquery should not be correlated, that is, it should not reference a column from a table in the outer query, or contain an aggregate that is evaluated in the outer query.

      这个优化也可以应用于作为 IN、NOT IN、EXISTS 或 NOT EXISTS 参数的表子查询,这些子查询不包含 GROUP BY。This optimization can also be applied to a table subquery which is the argument to IN, NOT IN, EXISTS, or NOT EXISTS, that does not contain a GROUP BY.

      此标志的默认值为 off,因为在大多数情况下,启用此优化不会产生显著的性能提升(在许多情况下甚至可能使查询运行得更慢),但你可以通过将 subquery_to_derived 标志设置为 on 来启用该优化。它主要用于测试。The default value for this flag is off, since, in most cases, enabling this optimization does not produce any noticeable improvement in performance (and in many cases can even make queries run more slowly), but you can enable the optimization by setting the subquery_to_derived flag to on. It is primarily intended for use in testing.

      示例,使用标量子查询:Example, using a scalar subquery:

      d
      mysql> CREATE TABLE t1(a INT);
      
      mysql> CREATE TABLE t2(a INT);
      
      mysql> INSERT INTO t1 VALUES ROW(1), ROW(2), ROW(3), ROW(4);
      
      mysql> INSERT INTO t2 VALUES ROW(1), ROW(2);
      
      mysql> SELECT * FROM t1
          ->     WHERE t1.a > (SELECT COUNT(a) FROM t2);
      +------+
      | a    |
      +------+
      |    3 |
      |    4 |
      +------+
      
      mysql> SELECT @@optimizer_switch LIKE '%subquery_to_derived=off%';
      +-----------------------------------------------------+
      | @@optimizer_switch LIKE '%subquery_to_derived=off%' |
      +-----------------------------------------------------+
      |                                                   1 |
      +-----------------------------------------------------+
      
      mysql> EXPLAIN SELECT * FROM t1 WHERE t1.a > (SELECT COUNT(a) FROM t2)\G
      *************************** 1. row ***************************
                 id: 1
        select_type: PRIMARY
              table: t1
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 4
           filtered: 33.33
              Extra: Using where
      *************************** 2. row ***************************
                 id: 2
        select_type: SUBQUERY
              table: t2
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 2
           filtered: 100.00
              Extra: NULL
      
      mysql> SET @@optimizer_switch='subquery_to_derived=on';
      
      
      mysql> SELECT @@optimizer_switch LIKE '%subquery_to_derived=off%';
      +-----------------------------------------------------+
      | @@optimizer_switch LIKE '%subquery_to_derived=off%' |
      +-----------------------------------------------------+
      |                                                   0 |
      +-----------------------------------------------------+
      
      mysql> SELECT @@optimizer_switch LIKE '%subquery_to_derived=on%';
      +----------------------------------------------------+
      | @@optimizer_switch LIKE '%subquery_to_derived=on%' |
      +----------------------------------------------------+
      |                                                  1 |
      +----------------------------------------------------+
      
      mysql> EXPLAIN SELECT * FROM t1 WHERE t1.a > (SELECT COUNT(a) FROM t2)\G
      *************************** 1. row ***************************
                 id: 1
        select_type: PRIMARY
              table: <derived2>
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 1
           filtered: 100.00
              Extra: NULL
      *************************** 2. row ***************************
                 id: 1
        select_type: PRIMARY
              table: t1
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 4
           filtered: 33.33
              Extra: Using where; Using join buffer (hash join)
      *************************** 3. row ***************************
                 id: 2
        select_type: DERIVED
              table: t2
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 2
           filtered: 100.00
              Extra: NULL
      

      正如在执行第二个 EXPLAIN 语句后立即执行 SHOW WARNINGS 可以看到的那样,在启用优化后,查询 SELECT * FROM t1 WHERE t1.a > (SELECT COUNT(a) FROM t2) 会以类似于此处所示的形式被重写:As can be seen from executing SHOW WARNINGS immediately following the second EXPLAIN statement, with the optimization enabled, the query SELECT * FROM t1 WHERE t1.a > (SELECT COUNT(a) FROM t2) is rewritten in a form similar to what is shown here:

      SELECT t1.a FROM t1
          JOIN  ( SELECT COUNT(t2.a) AS c FROM t2 ) AS d
                  WHERE t1.a > d.c;
      

      示例,使用带有 IN (subquery) 的查询:Example, using a query with IN (subquery):

      mysql> DROP TABLE IF EXISTS t1, t2;
      
      mysql> CREATE TABLE t1 (a INT, b INT);
      mysql> CREATE TABLE t2 (a INT, b INT);
      
      mysql> INSERT INTO t1 VALUES ROW(1,10), ROW(2,20), ROW(3,30);
      mysql> INSERT INTO t2
          ->    VALUES ROW(1,10), ROW(2,20), ROW(3,30), ROW(1,110), ROW(2,120), ROW(3,130);
      
      mysql> SELECT * FROM t1
          ->     WHERE   t1.b < 0
          ->             OR
          ->             t1.a IN (SELECT t2.a + 1 FROM t2);
      +------+------+
      | a    | b    |
      +------+------+
      |    2 |   20 |
      |    3 |   30 |
      +------+------+
      
      mysql> SET @@optimizer_switch="subquery_to_derived=off";
      
      mysql> EXPLAIN SELECT * FROM t1
          ->             WHERE   t1.b < 0
          ->                     OR
          ->                     t1.a IN (SELECT t2.a + 1 FROM t2)\G
      *************************** 1. row ***************************
                 id: 1
        select_type: PRIMARY
              table: t1
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 3
           filtered: 100.00
              Extra: Using where
      *************************** 2. row ***************************
                 id: 2
        select_type: DEPENDENT SUBQUERY
              table: t2
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 6
           filtered: 100.00
              Extra: Using where
      
      mysql> SET @@optimizer_switch="subquery_to_derived=on";
      
      mysql> EXPLAIN SELECT * FROM t1
          ->             WHERE   t1.b < 0
          ->                     OR
          ->                     t1.a IN (SELECT t2.a + 1 FROM t2)\G
      *************************** 1. row ***************************
                 id: 1
        select_type: PRIMARY
              table: t1
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 3
           filtered: 100.00
              Extra: NULL
      *************************** 2. row ***************************
                 id: 1
        select_type: PRIMARY
              table: <derived2>
         partitions: NULL
               type: ref
      possible_keys: <auto_key0>
                key: <auto_key0>
            key_len: 9
                ref: std2.t1.a
               rows: 2
           filtered: 100.00
              Extra: Using where; Using index
      *************************** 3. row ***************************
                 id: 2
        select_type: DERIVED
              table: t2
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 6
           filtered: 100.00
              Extra: Using temporary
      

      在执行EXPLAIN 对此查询后,检查并简化SHOW WARNINGS的结果显示,当启用subquery_to_derived 标志时,SELECT * FROM t1 WHERE t1.b < 0 OR t1.a IN (SELECT t2.a + 1 FROM t2) 会被重写为类似此处所示的形式:Checking and simplifying the result of SHOW WARNINGS after executing EXPLAIN on this query shows that, when the subquery_to_derived flag enabled, SELECT * FROM t1 WHERE t1.b < 0 OR t1.a IN (SELECT t2.a + 1 FROM t2) is rewritten in a form similar to what is shown here:

      SELECT a, b FROM t1
          LEFT JOIN (SELECT DISTINCT a + 1 AS e FROM t2) d
          ON t1.a = d.e
          WHERE   t1.b < 0
                  OR
                  d.e IS NOT NULL;
      

      示例,使用带有EXISTS (subquery) 的查询,以及与前一个示例相同的表和数据:Example, using a query with EXISTS (subquery) and the same tables and data as in the previous example:

      mysql> SELECT * FROM t1
          ->     WHERE   t1.b < 0
          ->             OR
          ->             EXISTS(SELECT * FROM t2 WHERE t2.a = t1.a + 1);
      +------+------+
      | a    | b    |
      +------+------+
      |    1 |   10 |
      |    2 |   20 |
      +------+------+
      
      mysql> SET @@optimizer_switch="subquery_to_derived=off";
      
      mysql> EXPLAIN SELECT * FROM t1
          ->             WHERE   t1.b < 0
          ->                     OR
          ->                     EXISTS(SELECT * FROM t2 WHERE t2.a = t1.a + 1)\G
      *************************** 1. row ***************************
                 id: 1
        select_type: PRIMARY
              table: t1
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 3
           filtered: 100.00
              Extra: Using where
      *************************** 2. row ***************************
                 id: 2
        select_type: DEPENDENT SUBQUERY
              table: t2
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 6
           filtered: 16.67
              Extra: Using where
      
      mysql> SET @@optimizer_switch="subquery_to_derived=on";
      
      mysql> EXPLAIN SELECT * FROM t1
          ->             WHERE   t1.b < 0
          ->                     OR
          ->                     EXISTS(SELECT * FROM t2 WHERE t2.a = t1.a + 1)\G
      *************************** 1. row ***************************
                 id: 1
        select_type: PRIMARY
              table: t1
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 3
           filtered: 100.00
              Extra: NULL
      *************************** 2. row ***************************
                 id: 1
        select_type: PRIMARY
              table: <derived2>
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 6
           filtered: 100.00
              Extra: Using where; Using join buffer (hash join)
      *************************** 3. row ***************************
                 id: 2
        select_type: DERIVED
              table: t2
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 6
           filtered: 100.00
              Extra: Using temporary
      

      如果在启用了 subquery_to_derived 后,在查询 SHOW WARNINGS 上运行 EXPLAIN 后执行 SELECT * FROM t1 WHERE t1.b < 0 OR EXISTS(SELECT * FROM t2 WHERE t2.a = t1.a + 1),并简化结果的第二行,我们可以看到它已被重写为类似于这样的形式:If we execute SHOW WARNINGS after running EXPLAIN on the query SELECT * FROM t1 WHERE t1.b < 0 OR EXISTS(SELECT * FROM t2 WHERE t2.a = t1.a + 1) when subquery_to_derived has been enabled, and simplify the second row of the result, we see that it has been rewritten in a form which resembles this:

      SELECT a, b FROM t1
      LEFT JOIN (SELECT DISTINCT 1 AS e1, t2.a AS e2 FROM t2) d
      ON t1.a + 1 = d.e2
      WHERE   t1.b < 0
              OR
              d.e1 IS NOT NULL;
      

      有关更多信息,请参见第 10.2.2.4 节,“使用合并或物化优化派生表、视图引用和公共表表达式”,以及第 10.2.1.19 节,“LIMIT 查询优化”,以及使用半连接转换优化 IN 和 EXISTS 子查询谓词。For more information, see Section 10.2.2.4, “Optimizing Derived Tables, View References, and Common Table Expressions with Merging or Materialization”, as well as Section 10.2.1.19, “LIMIT Query Optimization”, and Optimizing IN and EXISTS Subquery Predicates with Semijoin Transformations.

当你给 optimizer_switch 赋值时,未提及的标志将保持其当前值。这使得在单条语句中启用或禁用特定的优化器行为成为可能,而不会影响其他行为。该语句不依赖于其他优化器标志是否存在以及它们的值。假设所有索引合并优化都已启用:When you assign a value to optimizer_switch, flags that are not mentioned keep their current values. This makes it possible to enable or disable specific optimizer behaviors in a single statement without affecting other behaviors. The statement does not depend on what other optimizer flags exist and what their values are. Suppose that all Index Merge optimizations are enabled:

mysql> SELECT @@optimizer_switch\G
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,
                    index_merge_sort_union=on,index_merge_intersection=on,
                    engine_condition_pushdown=on,index_condition_pushdown=on,
                    mrr=on,mrr_cost_based=on,block_nested_loop=on,
                    batched_key_access=off,materialization=on,semijoin=on,
                    loosescan=on, firstmatch=on,
                    subquery_materialization_cost_based=on,
                    use_index_extensions=on,condition_fanout_filter=on,
                    derived_merge=on,use_invisible_indexes=off,skip_scan=on,
                    hash_join=on,subquery_to_derived=off,
                    prefer_ordering_index=on

如果服务器在某些查询中使用 Index Merge Union 或 Index Merge Sort-Union 访问方法,并且您想检查优化器在不使用这些方法时是否能表现更好,请按如下方式设置变量值:If the server is using the Index Merge Union or Index Merge Sort-Union access methods for certain queries and you want to check whether the optimizer can perform better without them, set the variable value like this:

mysql> SET optimizer_switch='index_merge_union=off,index_merge_sort_union=off';

mysql> SELECT @@optimizer_switch\G
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=off,
                    index_merge_sort_union=off,index_merge_intersection=on,
                    engine_condition_pushdown=on,index_condition_pushdown=on,
                    mrr=on,mrr_cost_based=on,block_nested_loop=on,
                    batched_key_access=off,materialization=on,semijoin=on,
                    loosescan=on, firstmatch=on,
                    subquery_materialization_cost_based=on,
                    use_index_extensions=on,condition_fanout_filter=on,
                    derived_merge=on,use_invisible_indexes=off,skip_scan=on,
                    hash_join=on,subquery_to_derived=off,
                    prefer_ordering_index=on