数据类型支持
MySQL现在支持在数据类型规范中将表达式用作默认值。这包括可以为以前无法分配默认值的BLOB、TEXT、GEOMETRY和JSON数据类型设置表达式作为默认值。
优化器
以下是新增的优化器改进:
-
MySQL现在支持不可见索引。不可见索引在优化器中根本不被使用,但在其他方面仍然正常维护。索引默认是可见的。不可见索引使得可以测试在查询性能上移除索引的影响,而不会造成不可逆的破坏性改变,如果发现索引是必需的,则需要撤销这些改变。
-
MySQL现在支持降序索引:在索引定义中使用DESC不再被忽略,而是导致键值按降序存储。以前,索引可以按相反顺序扫描,但会导致性能损失。降序索引可以按正向顺序扫描,这更高效。降序索引还使得优化器可以在多列索引上使用多种扫描顺序,其中某些列以升序排序,而其他列以降序排序。
-
MySQL现在支持创建函数索引关键部分,可以索引表达式的值而不是列的值。函数索引关键部分可以对无法进行索引的值进行索引,例如JSON值。
-
在MySQL 8.0.14及更高版本中,由常量文字表达式引起的无关紧要的WHERE条件在准备阶段被删除,而不是在优化阶段后面被删除。在过程的早期移除条件使得能够简化具有无关紧要条件的外连接查询的连接操作,例如下面的查询条件:
sqlSELECT * FROM t1 LEFT JOIN t2 ON condition_1 WHERE condition_2 OR 0 = 1
在准备阶段,优化器现在能够看到0 = 1始终为false,因此可以将OR 0 = 1这部分判定为多余,并将其移除,只留下以下内容:
sqlSELECT * FROM t1 LEFT JOIN t2 ON condition_1 where condition_2
现在,优化器可以将查询重写为内连接,如下所示:
sqlSELECT * FROM t1 LEFT JOIN t2 WHERE condition_1 AND condition_2
-
在MySQL 8.0.16及更高版本中,MySQL可以在优化时使用常量折叠来处理列与常量值之间的比较,其中常量值超出了列的类型的范围或位于范围边界上,而不是在执行时为每一行进行操作。例如,给定一个具有TINYINT UNSIGNED列c的表t,优化器可以将条件例如WHERE c < 256重写为WHERE 1(并完全优化掉该条件),或将WHERE c >= 255重写为WHERE c = 255。
-
从MySQL 8.0.16开始,与IN子查询一起使用的半连接优化现在也可以应用于EXISTS子查询。此外,优化器现在会解除子查询所附带的WHERE条件中的无关紧要的关联相等谓词,使其能够类似于IN子查询中的表达式进行处理;这适用于EXISTS和IN子查询。
-
从MySQL 8.0.17开始,服务器会在上下文化阶段内部将任何不完整的SQL谓词(即形式为WHERE value的谓词,其中value是列名或常量表达式,而且没有使用比较运算符)重写为WHERE value <> 0,以便查询解析器、查询优化器和查询执行器只需要处理完整的谓词。
这个变化的一个显著影响是,在布尔值上,EXPLAIN输出现在显示true和false,而不是1和0。
这个变化的另一个影响是,在SQL布尔上下文中评估JSON值将隐式与JSON整数0进行比较。考虑下面所示的创建和填充表的例子:
sqlmysql> CREATE TABLE test (id INT, col JSON); mysql> INSERT INTO test VALUES (1, '{"val":true}'), (2, '{"val":false}');
在之前的版本中,服务器在SQL布尔上下文中将提取的true或false值尝试转换为SQL布尔值,如下面使用IS TRUE的查询所示:
sqlmysql> SELECT id, col, col->"$.val" FROM test WHERE col->"$.val" IS TRUE; +------+---------------+--------------+ | id | col | col->"$.val" | +------+---------------+--------------+ | 1 | {"val": true} | true | +------+---------------+--------------+
在MySQL 8.0.17及更高版本中,将提取的值隐式与JSON整数0进行比较会得到不同的结果:
sqlmysql> SELECT id, col, col->"$.val" FROM test WHERE col->"$.val" IS TRUE; +------+----------------+--------------+ | id | col | col->"$.val" | +------+----------------+--------------+ | 1 | {"val": true} | true | | 2 | {"val": false} | false | +------+----------------+--------------+
从MySQL 8.0.21开始,您可以在执行测试之前使用JSON_VALUE()函数对提取的值进行类型转换,示例如下:
sqlmysql> SELECT id, col, col->"$.val" FROM test -> WHERE JSON_VALUE(col, "$.val" RETURNING UNSIGNED) IS TRUE; +------+---------------+--------------+ | id | col | col->"$.val" | +------+---------------+--------------+ | 1 | {"val": true} | true | +------+---------------+--------------+
从MySQL 8.0.21开始,服务器提供了一个警告:"在SQL布尔上下文中评估JSON值会隐式与JSON整数0进行比较;如果这不是您想要的,请考虑使用JSON_VALUE RETURNING将JSON转换为SQL数值类型,在SQL布尔上下文中以这种方式比较提取的值"。
-
在MySQL 8.0.17及更高版本中,拥有NOT IN (子查询)或NOT EXISTS (子查询)的WHERE条件会在内部转换为反连接。反连接返回表中所有行,其中没有与它连接的表中的行与连接条件匹配。这将消除子查询,可以加快查询执行速度,因为子查询的表现在在顶层处理。
这类似于外连接的IS NULL (Not exists)优化,并且重新使用了这个优化。
-
从MySQL 8.0.21开始,单表UPDATE或DELETE语句现在可以在许多情况下使用半连接转换或子查询结果存储。适用于以下形式的语句:
sql• UPDATE t1 SET t1.a=value WHERE t1.a IN (SELECT t2.a FROM t2) • DELETE FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2)
单表UPDATE或DELETE必须满足以下条件才能执行这种转换:
• UPDATE或DELETE语句使用具有[NOT] IN或[NOT] EXISTS谓词的子查询。
• 语句没有ORDER BY子句,也没有LIMIT子句。(多表版本的UPDATE和DELETE不支持ORDER BY或LIMIT。)
• 目标表不支持读取前写入删除(仅适用于NDB表)。
• 基于子查询中包含的任何提示和optimizer_switch的值,允许使用半连接或子查询结果存储。
当半连接优化用于合格的单表DELETE或UPDATE时,在优化器跟踪中可见:对于多表语句,跟踪中有一个join_optimization对象,而单表语句则没有。这种转换还可在EXPLAIN FORMAT=TREE或EXPLAIN ANALYZE的输出中看到:单表语句显示为"<not executable by iterator executor>",而多表语句报告了一个完整的计划。
从MySQL 8.0.21开始,使用InnoDB表的多表UPDATE语句支持半一致性读,适用于比REPEATABLE READ更弱的事务隔离级别。