MySQL现在支持在数据类型规范中将表达式用作默认值。这包括可以为以前无法分配默认值的BLOB、TEXT、GEOMETRY和JSON数据类型设置表达式作为默认值。
以下是新增的优化器改进:
SELECT * FROM t1 LEFT JOIN t2 ON condition_1 WHERE condition_2 OR 0 = 1
在准备阶段,优化器现在能够看到0 = 1始终为false,因此可以将OR 0 = 1这部分判定为多余,并将其移除,只留下以下内容:
SELECT * FROM t1 LEFT JOIN t2 ON condition_1 where condition_2
现在,优化器可以将查询重写为内连接,如下所示:
SELECT * FROM t1 LEFT JOIN t2 WHERE condition_1 AND condition_2
从MySQL 8.0.17开始,服务器会在上下文化阶段内部将任何不完整的SQL谓词(即形式为WHERE value的谓词,其中value是列名或常量表达式,而且没有使用比较运算符)重写为WHERE value <> 0,以便查询解析器、查询优化器和查询执行器只需要处理完整的谓词。
这个变化的一个显著影响是,在布尔值上,EXPLAIN输出现在显示true和false,而不是1和0。
这个变化的另一个影响是,在SQL布尔上下文中评估JSON值将隐式与JSON整数0进行比较。考虑下面所示的创建和填充表的例子:
mysql> CREATE TABLE test (id INT, col JSON);
mysql> INSERT INTO test VALUES (1, '{"val":true}'), (2, '{"val":false}');
?在之前的版本中,服务器在SQL布尔上下文中将提取的true或false值尝试转换为SQL布尔值,如下面使用IS TRUE的查询所示: mysql> 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进行比较会得到不同的结果:
mysql> 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()函数对提取的值进行类型转换,示例如下:
mysql> 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语句现在可以在许多情况下使用半连接转换或子查询结果存储。适用于以下形式的语句:
? 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更弱的事务隔离级别。