Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  Constant-Folding Optimization

10.2.1.14 常量折叠优化

现在,在查询优化期间,而不是在执行期间,对常量值和列值之间的比较进行处理,其中常量值超出范围或类型不正确。可以以这种方式处理的比较操作符包括 >>=<<=<>/!==<=>

考虑以下语句创建的表:

CREATE TABLE t (c TINYINT UNSIGNED NOT NULL);

在查询 SELECT * FROM t WHERE c < 256 中的 WHERE 条件包含整数常量 256,该常量超出 TINYINT UNSIGNED 列的范围。以前,这是通过将两个操作数都视为较大类型来处理的,但现在,因为允许的任何 c 值都小于常量,因此 WHERE 表达式可以折叠为 WHERE 1,因此查询被重写为 SELECT * FROM t WHERE 1

这使得优化器可以完全删除 WHERE 表达式。如果列 c 是可空的(即仅定义为 TINYINT UNSIGNED),则查询将被重写为:

SELECT * FROM t WHERE ti IS NOT NULL

折叠操作适用于 MySQL 支持的列类型和常量的比较,如下所示:

  • 整数列类型  整数类型与以下类型的常量进行比较:

    • 整数值  如果常量超出列类型的范围,则比较折叠为 1IS NOT NULL,如上所示。

      如果常量是范围边界,则比较折叠为 =。例如(使用同一个表):

      mysql> EXPLAIN SELECT * FROM t WHERE c >= 255;
      *************************** 1. row ***************************
                 id: 1
        select_type: SIMPLE
              table: t
         partitions: NULL
               type: ALL
      possible_keys: NULL
                key: NULL
            key_len: NULL
                ref: NULL
               rows: 5
           filtered: 20.00
              Extra: Using where
      1 row in set, 1 warning (0.00 sec)
      
      mysql> SHOW WARNINGS;
      *************************** 1. row ***************************
        Level: Note
         Code: 1003
      Message: /* select#1 */ select `test`.`t`.`ti` AS `ti` from `test`.`t` where (`test`.`t`.`ti` = 255)
      1 row in set (0.00 sec)
    • 浮点或固定点值  如果常量是十进制类型(例如 DECIMALREALDOUBLEFLOAT),且具有非零小数部分,则无法相等;折叠相应地。对于其他比较,根据符号将其四舍五入到整数值,然后按照已经描述的整数-整数比较处理。

      无法以 DECIMAL 表示的 REAL 值将被四舍五入到 .01 或 -.01,取决于符号,然后作为 DECIMAL 处理。

    • 字符串类型  尝试将字符串值解释为整数类型,然后将比较处理为整数值。如果失败,则尝试将值处理为 REAL

  • DECIMAL 或 REAL 列  十进制类型与以下类型的常量进行比较:

    • 整数值  对列值的整数部分执行范围检查。如果没有折叠结果,则将常量转换为具有与列值相同小数位数的 DECIMAL,然后将其作为 DECIMAL 检查(见下)。

    • 十进制或实数值。 检查溢出(即,常量的整数部分的数字是否超过列的十进制类型允许的数字)。如果是这样,折叠。

      如果常量的有效小数位数超过列的类型,截断常量。如果比较操作符是 =<>,折叠。如果操作符是 >=<=,调整操作符以适应截断。例如,如果列的类型是 DECIMAL(3,1)SELECT * FROM t WHERE f >= 10.13 变为 SELECT * FROM t WHERE f > 10.1

      如果常量的十进制位数少于列的类型,将其转换为具有相同数字的常量。对于实数值的下溢(即,太少的小数位数以表示它),将常量转换为十进制 0。

    • 字符串值。 如果值可以解释为整数类型,则将其作为整数类型处理。否则,尝试将其作为 REAL 处理。

  • FLOAT 或 DOUBLE 列。 FLOAT(m,n)DOUBLE(m,n) 值与常量比较的处理方式如下:

    如果值超出列的范围,折叠。

    如果值的小数位数超过 n,截断,并在折叠时进行补偿。对于 =<> 比较,折叠到 TRUEFALSEIS [NOT] NULL,如前所述;对于其他操作符,调整操作符。

    如果值的小数位数超过 m,折叠。

限制。 该优化不能在以下情况下使用:

  1. 使用 BETWEENIN 比较。

  2. 使用 BIT 列或使用日期或时间类型的列。

  3. 在准备阶段为准备语句,尽管可以在执行阶段应用该优化。这是因为,在语句准备阶段,常量的值尚未知晓。