文档主页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


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

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. 在预处理语句的准备阶段,尽管可以在实际执行预处理语句的优化阶段应用此优化。这是因为在语句准备期间,常量的值尚不清楚。