# 普通的公用表表达式
WITH
cte1 AS (SELECT a, b FROM table1),
cte2 AS (SELECT c, d FROM table2)
SELECT b, d FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;
# 递归公用表表达式
WITH RECURSIVE cte (n) AS
(
SELECT 1
UNION ALL
SELECT n + 1 FROM cte WHERE n < 5
)
SELECT * FROM cte;
3. 窗口函数
窗口函数,也称为分析函数,可针对一组行进行计算,并为每行返回一个结果。
这一点与聚合函数不同。聚合函数只能为每个分组返回一个结果。
窗口函数中的 OVER 子句定义了所要计算行的行窗口。
看下面这个示例,都是为了实现行号,只不过在 MySQL 8.0 之前,需借助于自定义变量,而在 MySQL 8.0 中,可以直接使用 ROW_NUMBER()。
# MySQL 5.7
SET @row_number = 0;
SELECT dept_no, dept_name,
(@row_number:=@row_number + 1) AS row_num
FROM departments ORDER BY dept_no;
# MySQL 8.0
SELECT dept_no, dept_name,
ROW_NUMBER() OVER (ORDER BY dept_no) AS row_num
FROM departments;
4. 支持将表达式作为默认值
下面是官方文档中的一个示例。
CREATE TABLE t1 (
# 文本默认值
i INT DEFAULT 0,
c VARCHAR(10) DEFAULT '',
# 表达式默认值
f FLOAT DEFAULT (RAND() * RAND()),
b BINARY(16) DEFAULT (UUID_TO_BIN(UUID())),
d DATE DEFAULT (CURRENT_DATE + INTERVAL 1 YEAR),
p POINT DEFAULT (Point(0,0)),
j JSON DEFAULT (JSON_ARRAY())
);
注意,表达式默认值必须放到括号内。
从 MySQL 8.0.13 开始,BLOB, TEXT, GEOMETRY 和 JSON 字段允许设置表达式默认值。例如,
# 创建不可见索引
ALTER TABLE t1 ADD INDEX k_idx (k) INVISIBLE;
# 将索引设置为不可见
ALTER TABLE t1 ALTER INDEX i_idx INVISIBLE;
# 将索引设置为可见
ALTER TABLE t1 ALTER INDEX i_idx VISIBLE;
优化器默认不会使用不可见索引。如果要使用,可设置 optimizer_switch。
SET SESSION optimizer_switch='use_invisible_indexes=on';
SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */ * FROM t1 WHERE k = 1;
SELECT ... FOR SHARE 和 SELECT ... FOR UPDATE 语句中引入 NOWAIT 和 SKIP LOCKED 选项,用来解决电商场景热点行问题。
session1> CREATE TABLE t(id INT PRIMARY KEY);
Query OK, 0 rows affected (0.06 sec)
session1> INSERT INTO t VALUES(1),(2),(3);
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0
session1> BEGIN;
Query OK, 0 rows affected (0.00 sec)
session1> SELECT * FROM t WHERE id=2 FOR UPDATE;
+----+
| id |
+----+
| 2 |
+----+
1 row in set (0.00 sec)
# 如果需要加锁的行被其它事务锁定,指定 NOWAIT 会立即报错,不会等到锁超时
session2> SELECT * FROM t WHERE id = 2 FOR UPDATE NOWAIT;
ERROR 3572 (HY000): Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set.
# 指定 SKIP LOCKED 则会跳过锁定行
session2> SELECT * FROM t FOR UPDATE SKIP LOCKED;
+----+
| id |
+----+
| 1 |
| 3 |
+----+
2 rows in set (0.00 sec)
16. 分组排序
不再支持 GROUP BY ASC/DESC 语法。例如,
GROUP BY dept_no ASC;
如果要对分组列进行排序,需显式指定排序列,例如,
GROUP BY dept_no ORDER BY dept_no;
17. 分区表
通用的分区接口(Handler)已从代码层移除。
在 MySQL 8.0 中,如果要使用分区表,只能使用 InnoDB 存储引擎。
18. 正则表达式
在 MySQL 8.0 中,正则表达式底层库由 Henry Spencer 调整为了 International Components for Unicode (ICU)。Spencer 库的部分语法不再支持。
mysql> CREATE TABLE slowtech.t1(id INT);
ERROR 3750 (HY000): Unable to create or change a table without a primary key, when the system variable 'sql_require_primary_key' is set. Add a primary key to the table or unset this variable to avoid this message. Note that tables without a primary key can cause performance problems in row-based replication, so please consult your DBA before changing this setting.
20. 隐式主键
在 MySQL 8.0.30 中,引入了 sql_generate_invisible_primary_key 参数可为没有显式设置主键的表创建一个隐式主键。默认为 OFF。
这些新特性涉及的范围包括:字符集、语法、索引、JSON、从 MySQL 5.7 升级到 MySQL 8.0 需要注意的不兼容项、参数、Hint等。
1. 字符集
默认字符集由 latin1 调整为 utf8mb4。
在 MySQL 8.0 中,utf8mb4 默认的校对集是 utf8mb4_0900_ai_ci,在 MySQL 5.7 中则是 utf8mb4_general_ci。
utf8mb4_0900_ai_ci 中的 0900 指的是 Unicode 9.0 规范,ai 是 accent insensitivity 的缩写,指的是不区分音调,ci 是 case insensitivity 的缩写,指的是不区分大小写。
2. 公用表表达式(CTE)
CTE,简单来说,就是一个命名的临时结果集。
只需定义一次,即可多次使用。
使用 CTE 不仅让 SQL 语句变得简洁,同时也提升了 SQL 语句的可读性。
3. 窗口函数
窗口函数,也称为分析函数,可针对一组行进行计算,并为每行返回一个结果。
这一点与聚合函数不同。聚合函数只能为每个分组返回一个结果。
窗口函数中的 OVER 子句定义了所要计算行的行窗口。
看下面这个示例,都是为了实现行号,只不过在 MySQL 8.0 之前,需借助于自定义变量,而在 MySQL 8.0 中,可以直接使用 ROW_NUMBER()。
4. 支持将表达式作为默认值
下面是官方文档中的一个示例。
注意,表达式默认值必须放到括号内。
从 MySQL 8.0.13 开始,BLOB, TEXT, GEOMETRY 和 JSON 字段允许设置表达式默认值。例如,
5. 支持 CHECK 约束
看下面这个示例。
6. 隐藏列
隐藏列是 MySQL 8.0.23 引入的新特性。对于隐藏列,只有显式指定才能访问。无论是在查询,还是 DML 语句中。
如果是通过 SELECT * 查询,则不会返回隐藏列的内容。
7. 不可见索引
对于冗余索引,在执行删除操作之前,可以先将它设置为不可见,然后观察一段时间,确定对业务没有影响再执行删除操作。
优化器默认不会使用不可见索引。如果要使用,可设置 optimizer_switch。
8. 降序索引
对于涉及到多列,但排序顺序又不一致的排序操作,可以通过降序索引来优化。
如 ORDER BY c1 ASC, c2 DESC 这个排序操作就可以通过下面这个索引来优化。
9. 函数索引
函数索引允许对表达式创建索引,在此之前,只能对列或列的前缀创建索引。
10. VALUES
VALUES 是 MySQL 8.0.19 开始支持的语法,它会以表的形式返回一行或多行数据。
行数据通过 ROW() 函数来构造。函数中的元素既可以是标量值,也可以是表达式。
列名是 column_x,其中,x 是序号,从 0 开始递增。
11. INTERSECT 和 EXCEPT
MySQL 8.0.31 开始支持 INTERSECT 和 EXCEPT,分别用来取两个集合的交集和差集。
12. 唯一键冲突
唯一键冲突的报错信息会输出表名,在 MySQL 5.7 中,只会输出唯一键名。
13. 查询改写插件
查询改写插件在 MySQL 8.0.12 之前只支持 SELECT 语句,从 MySQL 8.0.12 开始支持 INSERT,REPLACE,UPDATE 和 DELETE 语句。
14. JSON
JSON 字段支持部分更新,极大提升了 JSON 字段的处理性能。
看下面这个测试结果。
JSON 的具体用法可参考:一文说透 MySQL JSON 数据类型
15. NOWAIT 和 SKIP LOCKED
SELECT ... FOR SHARE 和 SELECT ... FOR UPDATE 语句中引入 NOWAIT 和 SKIP LOCKED 选项,用来解决电商场景热点行问题。
16. 分组排序
不再支持 GROUP BY ASC/DESC 语法。例如,
如果要对分组列进行排序,需显式指定排序列,例如,
17. 分区表
通用的分区接口(Handler)已从代码层移除。
在 MySQL 8.0 中,如果要使用分区表,只能使用 InnoDB 存储引擎。
18. 正则表达式
在 MySQL 8.0 中,正则表达式底层库由 Henry Spencer 调整为了 International Components for Unicode (ICU)。Spencer 库的部分语法不再支持。
两者用法上的具体差异可参考:不可不知的 MySQL 升级利器及 5.7 升级到 8.0 的注意事项
19. 表上必须存在主键
引入了 sql_require_primary_key 参数可强制要求表上必须存在主键。默认为 OFF。
20. 隐式主键
在 MySQL 8.0.30 中,引入了 sql_generate_invisible_primary_key 参数可为没有显式设置主键的表创建一个隐式主键。默认为 OFF。
看下面这个示例。
21. Hint
引入了多个 Hint。
在 MySQL 5.7 中,Hint 只有 13 个。在 MySQL 8.0 中,则新增到了 37 个。
新增的 Hint 中,其中一个是 SET_VAR,可在语句级别调整参数的会话值。例如,
收录于合集 #MySQL
原文:https://mp.weixin.qq.com/s/AZEJJE3YN2GRWADF2X7rMA