常量折叠优化:修订间差异
无编辑摘要 |
无编辑摘要 |
||
第86行: | 第86行: | ||
*限制。以下情况下无法使用此优化: | *限制。以下情况下无法使用此优化: | ||
**使用BETWEEN或IN进行比较的情况。 | **使用BETWEEN或IN进行比较的情况。 | ||
**使用BIT列或使用日期或时间类型的列的情况。 | **使用BIT列或使用日期或时间类型的列的情况。 | ||
**在准备阶段的预处理语句中,尽管在实际执行预处理语句时可以在优化阶段应用此优化。这是因为在语句准备阶段,常量的值尚未确定。 | **在准备阶段的预处理语句中,尽管在实际执行预处理语句时可以在优化阶段应用此优化。这是因为在语句准备阶段,常量的值尚未确定。 |
2023年7月19日 (三) 08:09的最新版本
在查询优化过程中,将那些常量和列值之间的比较,其中常量值超出范围或与列类型不匹配的情况,不再逐行处理,而是一次性处理。可以采用这种方式处理的比较运算符有 >、>=、<、<=、<>/!=、= 和<=>。
考虑以下语句创建的表:
CREATE TABLE t (c TINYINT UNSIGNED NOT NULL);
在查询 SELECT * FROM t WHERE c < 256 的 WHERE 条件中,包含了超出 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列类型进行常量比较的,具体如下所示:
- 整数列类型。整数类型与以下类型的常量进行比较,如下所述:
1、整数值。如果常量超出列类型的范围,比较将被简化为1或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)
2、浮点数或定点数值。如果常量是十进制类型(如DECIMAL、REAL、DOUBLE或FLOAT),并且具有非零的小数部分,则它不能相等;相应地进行简化。对于其他比较,根据符号四舍五入为整数值,然后执行范围检查,并按照整数-整数比较的方式处理。
无法表示为DECIMAL的REAL值会四舍五入为.01或-.01,然后按照DECIMAL处理。
3、字符串类型。尝试将字符串值解释为整数类型,然后按照整数值之间的比较进行处理。如果失败,则尝试将该值处理为REAL类型。
- DECIMAL或REAL列。根据以下规则比较十进制类型的常量:
1、整数值。对列值的整数部分进行范围检查。如果无法简化,则将常量转换为与列值具有相同小数位数的DECIMAL类型,然后将其作为DECIMAL进行检查(见下文)。
2、DECIMAL或REAL值。检查是否溢出(即常量的整数部分是否比列的小数类型允许的位数多)。如果是,则进行简化。
如果常量的小数位数比列的类型更多,则截断常量。如果比较运算符是=或< >,则进行简化。如果运算符是>=或<=,则由于截断而调整运算符。例如,如果列的类型是DECIMAL(3,1),SELECT * FROM t WHERE f >= 10.13将变为SELECT * FROM t WHERE f > 10.1。
如果常量的小数位数少于列的类型,则将其转换为具有相同位数的常量。对于REAL值的下溢(即表示不了足够的小数位数),将常量转换为0的DECIMAL类型。
3、字符串值。如果该值可以解释为整数类型,则按照该类型处理。否则,尝试将其作为REAL类型处理。
- FLOAT或DOUBLE列。将与常量进行比较的FLOAT(m,n)或DOUBLE(m,n)值的处理方式如下:
如果值超出了列的范围,进行简化。
如果值的小数位数超过n,进行截断,并在简化过程中进行补偿。对于=和<>的比较,根据之前描述的方式简化为TRUE、FALSE或IS [NOT] NULL;对于其他操作符,调整操作符。
如果值的整数位数超过了m,进行简化。
- 限制。以下情况下无法使用此优化:
- 使用BETWEEN或IN进行比较的情况。
- 使用BIT列或使用日期或时间类型的列的情况。
- 在准备阶段的预处理语句中,尽管在实际执行预处理语句时可以在优化阶段应用此优化。这是因为在语句准备阶段,常量的值尚未确定。