Documentation Home
MySQL 8.0 参考手册  / 第8章优化  / 8.2 优化SQL语句  / 8.2.1 优化 SELECT 语句  /  8.2.1.14 常量折叠优化

8.2.1.14 常量折叠优化

常量和列值之间的比较,其中常量值超出范围或相对于列类型的类型错误现在在查询优化期间处理一次,而不是在执行期间逐行处理。可以用这种方式处理的比较有 >, >=, <, <=, <>/ !=, =, 和<=>

考虑由以下语句创建的表:

CREATE TABLE t (c TINYINT UNSIGNED NOT NULL);

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

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

SELECT * FROM t WHERE ti IS NOT NULL

与支持的 MySQL 列类型相比,对常量执行折叠,如下所示:

  • 整数列类型。  整数类型与以下类型的常量进行比较,如下所述:

    • 整数值。  如果常量超出列类型的范围,则比较折叠为1or IS 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)
    • 浮点或定点值。  如果常量是小数类型之一(例如 DECIMAL, REAL, DOUBLE, 或 FLOAT)并且有非零小数部分,则它不能相等;相应地折叠。对于其他比较,根据符号向上或向下舍入到整数值,然后执行范围检查并按照整数-整数比较所述进行处理。

      REAL太小而无法表示 的值DECIMAL根据符号四舍五入为 .01 或 -.01,然后作为 .01 处理DECIMAL

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

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

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

    • DECIMAL 或 REAL 值。  检查溢出(即常量的整数部分中的位数是否多于列的小数类型所允许的位数)。如果是这样,弃牌。

      如果常量的有效小数位数多于列的类型,则截断该常量。如果比较运算符是=or <>,则折叠。如果运算符是 >=<=,则由于截断而调整运算符。例如,如果列的类型是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 小数位,则截断,并在折叠期间进行补偿。对于 =<> 比较,折叠到TRUE, FALSE, 或IS [NOT] NULL如前所述;对于其他运营商,调整运营商。

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

限制。  此优化不能用于以下情况:

  1. 使用BETWEEN或 进行比较IN

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

  3. 在准备语句的准备阶段,虽然它可以在准备语句实际执行时的优化阶段应用。这是因为在语句准备期间,常量的值尚不清楚。