文档首页
MySQL 9.0 参考手册
相关文档 下载此手册

MySQL 9.0 参考手册  /  ...  /  常量折叠优化

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)并且具有非零小数部分,则它不能相等;相应地进行折叠。对于其他比较,根据符号向上或向下舍入到整数值,然后根据已描述的整数-整数比较执行范围检查并处理。

      一个小到无法表示为 DECIMALREAL 值将根据符号舍入为 .01 或 -.01,然后作为 DECIMAL 处理。

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

  • DECIMAL 或 REAL 列。 十进制类型与以下类型的常量比较,如这里所述

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

    • DECIMAL 或 REAL 值。 检查溢出(即,常量在其整数部分中的位数是否超过列的十进制类型允许的位数)。如果是,则进行折叠。

      如果常量具有比列类型更多的小数位,则截断常量。如果比较运算符是 =<>,则进行折叠。如果运算符是 >=<=,则由于截断而调整运算符。例如,如果列类型是 DECIMAL(3,1),则 SELECT * FROM t WHERE f >= 10.13 将变为 SELECT * FROM t WHERE f > 10.1

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

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

  • FLOAT 或 DOUBLE 列.  与常量比较的 FLOAT(m,n)DOUBLE(m,n) 值将按以下方式处理

    如果值超过列的范围,则进行折叠。

    如果值的小数位数超过 n 位,则截断,并在折叠期间进行补偿。对于 =<> 比较,将折叠为 TRUEFALSEIS [NOT] NULL,如前所述;对于其他运算符,调整运算符。

    如果值超过 m 位整数位,则进行折叠。

限制.  在以下情况下,无法使用此优化

  1. 使用 BETWEENIN 的比较。

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

  3. 在准备预处理语句的阶段,尽管在实际执行预处理语句的优化阶段可以应用它。这是因为在准备语句期间,常量的值尚不可知。