Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 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)并且有非零小数部分,它不能等于;折叠相应。对于其他比较,根据符号向上或下舍入到整数值,然后按照整数-整数比较方式处理。

      太小的 REAL 值将被舍入到 .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. 在预准备语句的准备阶段,虽然可以在实际执行语句时进行优化,但是在语句准备时不能,因为在语句准备时常量值还未知。