关键词:MySQL8, 新特性, 隐藏索引, 窗口函数, CTE, 降序索引, 函数索引, 原子DDL
MySQL 5.7将于2023年10月31日停止支持,官方不再进行代码维护。MySQL 8.0全内存访问可轻易跑到200W QPS,I/O极端高负载场景跑到16W QPS,性能提升显著。除此之外,MySQL 8还新增了大量实用功能。本文将从账户安全、索引增强、通用表表达式、窗口函数等多个维度,全面解析MySQL 8.0的新特性,帮助你顺利升级到MySQL 8。
目录
- [MySQL 8.0简介](#MySQL 8.0简介)
- 账户与安全增强
- 索引增强
- 通用表表达式(CTE)
- 窗口函数
- 原子DDL操作
- JSON增强
- InnoDB其他改进
1. MySQL 8.0简介
MySQL 5.7生命周期结束
- MySQL 5.7 将于2023年10月31日停止支持
- 官方不再进行后续代码维护
- 建议升级到MySQL 8.0以获得持续支持
MySQL 8.0性能提升
| 场景 | QPS性能 |
|---|---|
| 全内存访问 | 轻易跑到 200W QPS |
| I/O极端高负载场景 | 跑到 16W QPS |
2. 账户与安全增强
2.1 用户创建和授权分离
MySQL 5.7及之前版本:
sql
-- 用户创建和授权可以一起执行
GRANT ALL PRIVILEGES ON *.* TO 'lijin'@'%' IDENTIFIED BY 'Lijin@2022';
MySQL 8.0版本:
sql
-- 用户创建和授权必须分开执行
-- 步骤1:创建用户
CREATE USER 'lijin'@'%' IDENTIFIED BY 'Lijin@2022';
-- 步骤2:授权
GRANT ALL PRIVILEGES ON *.* TO 'lijin'@'%';
注意:MySQL 8.0中不能将用户创建和授权语句合并执行。
2.2 认证插件更新
MySQL 8.0默认认证插件变更:
| 版本 | 默认认证插件 |
|---|---|
| MySQL 5.7 | mysql_native_password |
| MySQL 8.0 | caching_sha2_password |
查看当前认证插件:
sql
SHOW VARIABLES LIKE 'default_authentication%';
-- 查看所有用户的认证插件
SELECT user, host, plugin FROM mysql.user;
兼容性问题:
- 如果客户端没有更新,可能连接不上MySQL 8.0
- 老版本的Navicat等工具可能无法正常连接
解决方案1:修改配置文件(需要重启)
ini
# my.cnf
[mysqld]
default_authentication_plugin=mysql_native_password
解决方案2:动态修改用户认证方式(无需重启)
sql
-- 修改指定用户的认证插件
ALTER USER 'lijin'@'%' IDENTIFIED WITH mysql_native_password BY 'Lijin@2022';
2.3 密码管理
MySQL 8.0开始允许限制重复使用以前的密码,并加入了密码修改管理功能。
查看密码相关变量:
sql
SHOW VARIABLES LIKE 'password%';
密码历史设置:
| 变量名 | 说明 |
|---|---|
password_history |
不能和最近N次密码一致 |
password_reuse_interval |
按照天数限制密码重复使用 |
password_require_current |
是否需要校验旧密码(OFF不校验,ON校验) |
全局级设置:
sql
-- 修改密码不能和最近3次一致
SET PERSIST password_history = 3;
用户级设置:
sql
-- 为指定用户设置密码历史策略
ALTER USER 'lijin'@'%' PASSWORD HISTORY 3;
-- 查看用户的密码历史设置
SELECT user, host, Password_reuse_history FROM mysql.user;
要求校验旧密码(针对非root用户):
sql
SET PERSIST password_require_current = ON;
3. 索引增强
3.1 隐藏索引
概念:MySQL 8.0开始支持隐藏索引(invisible index),隐藏索引不会被优化器使用,但仍然需要进行维护。
应用场景:
-
软删除
- 线上经常删除和创建索引,如果删除了发现删错了,又需要重新创建
- 先把索引变成隐藏索引(查询优化器用不上)
- 最后确定要删除时再进行删除操作
-
灰度发布
- 想在线上进行测试,先创建一个隐藏索引,不影响当前生产环境
- 通过测试发现索引没问题,直接把隐藏索引改成正式索引
创建隐藏索引:
sql
-- 创建表
CREATE TABLE t1(i INT, j INT);
-- 创建正常索引
CREATE INDEX i_idx ON t1(i);
-- 创建隐藏索引
CREATE INDEX j_idx ON t1(j) INVISIBLE;
查看索引信息:
sql
SHOW INDEX FROM t1\G
测试隐藏索引:
sql
-- 查看查询是否使用索引
EXPLAIN SELECT * FROM t1 WHERE i = 1; -- 会使用i_idx
EXPLAIN SELECT * FROM t1 WHERE j = 1; -- 不会使用j_idx(隐藏索引)
让优化器看到隐藏索引(会话级别):
sql
-- 查看优化器参数
SELECT @@optimizer_switch\G;
-- 开启隐藏索引可见
SET SESSION optimizer_switch = 'use_invisible_indexes=on';
切换索引可见性:
sql
-- 隐藏索引变为可见
ALTER TABLE t1 ALTER INDEX j_idx VISIBLE;
-- 正常索引变为隐藏
ALTER TABLE t1 ALTER INDEX j_idx INVISIBLE;
限制:不能把主键设置成隐藏索引(MySQL做了限制)。
3.2 降序索引
MySQL 8.0开始真正支持降序索引(descending index)。
特点:
- 只有InnoDB存储引擎支持降序索引
- 只支持BTREE降序索引
- MySQL 8.0不再对GROUP BY操作进行隐式排序
创建降序索引:
sql
CREATE TABLE t2(
c1 INT,
c2 INT,
INDEX idx1(c1 ASC, c2 DESC) -- c1升序,c2降序
);
查看表结构:
sql
SHOW CREATE TABLE t2\G
MySQL 8.0会显示升序/降序信息,而5.7不会显示。
插入测试数据:
sql
INSERT INTO t2(c1, c2) VALUES(1, 100), (2, 200), (3, 150), (4, 50);
使用降序索引查询:
sql
-- 会使用索引(不需要额外排序)
EXPLAIN SELECT * FROM t2 ORDER BY c1, c2 DESC;
-- MySQL 5.7需要额外的排序操作
-- MySQL 8.0可以直接使用索引
GROUP BY不再隐式排序:
MySQL 8.0中GROUP BY不再默认排序:
sql
-- 8.0版本:不会自动排序
SELECT COUNT(*), c2 FROM t2 GROUP BY c2;
-- 需要手动添加ORDER BY
SELECT COUNT(*), c2 FROM t2 GROUP BY c2 ORDER BY c2;
3.3 函数索引
问题背景:如果在查询中加入了函数,普通索引不会生效。
MySQL 8.0.13开始支持在索引中使用函数(表达式)的值,支持JSON数据的索引。
函数索引基于虚拟列功能实现。
创建函数索引(表达式):
sql
-- 创建表
CREATE TABLE t3(c1 VARCHAR(10), c2 VARCHAR(10));
-- 创建普通索引
CREATE INDEX idx_c1 ON t3(c1);
-- 创建函数索引(大写转换)
CREATE INDEX func_idx ON t3((UPPER(c2)));
测试函数索引:
sql
-- 普通索引不会生效(使用了函数)
EXPLAIN SELECT * FROM t3 WHERE UPPER(c1) = 'ABC';
-- 函数索引会生效
EXPLAIN SELECT * FROM t3 WHERE UPPER(c2) = 'ABC';
创建函数索引(JSON):
sql
-- 创建JSON函数索引
CREATE TABLE t4(
data JSON,
INDEX ((CAST(data->>'$.name' AS CHAR(25))))
);
-- 查询使用函数索引
EXPLAIN SELECT * FROM t4 WHERE CAST(data->>'$.name' AS CHAR(25)) = 'lijin';
原理:函数索引相当于新增了一个列,这个列根据函数进行计算,然后使用计算后的列作为索引。
4. 通用表表达式(CTE)
MySQL 8.0开始支持通用表表达式(Common Table Expression,CTE),即WITH子句。
简单入门示例
sql
WITH RECURSIVE cte(n) AS (
SELECT 1
UNION ALL
SELECT n + 1 FROM cte WHERE n < 10
)
SELECT * FROM cte;
结果:返回1到10的数字。
执行过程:
- 首先执行
SELECT 1,得到结果n=1 - 把n=1送入UNION ALL下面的
SELECT n+1 FROM cte WHERE n < 10 - 递归调用,直到n >= 10
递归CTE实际案例
场景:查询员工的上下级关系
表结构:
sql
CREATE TABLE staff (
id INT,
name VARCHAR(50),
m_id INT -- 上级ID
);
递归CTE查询上下级关系:
sql
WITH RECURSIVE staff_view(id, name, m_id) AS (
-- 递归起始:查询顶级员工(m_id=0)
SELECT id, name, CAST(id AS CHAR(200))
FROM staff
WHERE m_id = 0
UNION ALL
-- 递归部分:查询下级员工
SELECT s2.id, s2.name, CONCAT(s1.m_id, '-', s2.id)
FROM staff_view AS s1
JOIN staff AS s2 ON s1.id = s2.m_id
)
SELECT * FROM staff_view ORDER BY id;
优势:
- 上下级层级有4、5、6甚至更多层,都可以帮助遍历出来
- 老的方式需要写复杂的SQL,递归CTE更加简洁
CTE总结
- CTE类似于派生表,就像语句级别的临时表或视图
- CTE可以在查询中多次引用
- CTE可以引用其他CTE
- CTE支持递归
- CTE支持SELECT/INSERT/UPDATE/DELETE等语句
5. 窗口函数
MySQL 8.0支持窗口函数(Window Function),也称分析函数。
窗口函数与分组聚合函数类似,但每一行数据都生成一个结果。
聚合窗口函数
普通分组聚合(以国家统计):
sql
SELECT country, SUM(sum)
FROM sales
GROUP BY country
ORDER BY country;
窗口函数聚合(以国家汇总,保留所有行):
sql
SELECT
year, country, product, sum,
SUM(sum) OVER (PARTITION BY country) AS country_sum
FROM sales
ORDER BY country, year, product, sum;
计算平均值:
sql
SELECT
year, country, product, sum,
SUM(sum) OVER (PARTITION BY country) AS country_sum,
AVG(sum) OVER (PARTITION BY country) AS country_avg
FROM sales
ORDER BY country, year, product, sum;
专用窗口函数
| 类型 | 函数 |
|---|---|
| 序号函数 | ROW_NUMBER()、RANK()、DENSE_RANK() |
| 分布函数 | PERCENT_RANK()、CUME_DIST() |
| 前后函数 | LAG()、LEAD() |
| 头尾函数 | FIRST_VALUE()、LAST_VALUE() |
| 其他函数 | NTH_VALUE()、NTILE() |
排名示例
sql
SELECT
YEAR,
country,
product,
sum,
ROW_NUMBER() OVER (ORDER BY sum) AS 'rank',
RANK() OVER (ORDER BY sum) AS 'rank_1'
FROM sales;
ROW_NUMBER() vs RANK()区别:
- ROW_NUMBER():连续排名,1、2、3、4...
- RANK():跳跃排名,1、1、3、4...(相同值排名相同,跳过后续序号)
累计求和示例
sql
SELECT
YEAR,
country,
product,
sum,
SUM(sum) OVER (
PARTITION BY country
ORDER BY sum
ROWS UNBOUNDED PRECEDING
) AS sum_1
FROM sales
ORDER BY country, sum;
6. 原子DDL操作
MySQL 8.0开始支持原子DDL操作,与表相关的原子DDL只支持InnoDB存储引擎。
原子DDL操作内容:
- 更新数据字典
- 存储引擎层的操作
- 在binlog中记录DDL操作
支持的DDL:
| 对象 | 操作 |
|---|---|
| 数据库 | CREATE、ALTER、DROP |
| 表空间 | CREATE、ALTER、DROP |
| 表 | CREATE、ALTER、DROP、TRUNCATE TABLE |
| 索引 | CREATE、ALTER、DROP |
| 存储程序 | CREATE、ALTER、DROP |
| 触发器 | CREATE、ALTER、DROP |
| 视图 | CREATE、ALTER、DROP |
| UDF | CREATE、ALTER、DROP |
| 用户和角色 | CREATE、ALTER、DROP、RENAME |
| 权限 | GRANT、REVOKE |
原子DDL示例
sql
DROP TABLE t1, t2;
场景:只有t1表,没有t2表
| 版本 | 表现 |
|---|---|
| MySQL 5.7 | 删除t1表,报错(非原子操作) |
| MySQL 8.0 | 报错,不会删除t1表(原子操作) |
原子性保证:要么全部成功,要么全部失败。
7. JSON增强
MySQL 8.0对JSON数据类型进行了大量增强。
官方文档 :MySQL 8.0 JSON Data Type
主要增强:
- JSON数据类型的性能优化
- 新增的JSON函数
- JSON路径语法增强
- 排序和比较改进
8. InnoDB其他改进
8.1 自增列持久化
问题:MySQL 5.7及早期版本,InnoDB自增列计数器(AUTO_INCREMENT)的值只存储在内存中。
MySQL 8.0改进:
- 每次变化时将自增计数器的最大值写入redo log
- 每次检查点时将其写入引擎私有的系统表
- 解决了长期以来的自增字段值可能重复的bug
8.2 死锁检查控制
MySQL 8.0(MySQL 5.7.15)增加了新的动态变量,用于控制系统是否执行InnoDB死锁检查。
sql
-- 查看死锁检查设置
SHOW VARIABLES LIKE 'innodb_deadlock_detect';
适用场景:对于高并发的系统,禁用死锁检查可能带来性能提高。
8.3 锁定语句选项
SELECT ... FOR SHARE 和 SELECT ... FOR UPDATE 中支持 NOWAIT、SKIP LOCKED 选项。
| 选项 | 说明 |
|---|---|
| NOWAIT | 如果请求的行被其他事务锁定,语句立即返回 |
| SKIP LOCKED | 从返回的结果集中移除被锁定的行 |
示例:
sql
-- 立即返回,不等待锁
SELECT * FROM t1 WHERE id = 1 FOR UPDATE NOWAIT;
-- 跳过被锁定的行
SELECT * FROM t1 WHERE status = 'pending' FOR UPDATE SKIP LOCKED;
8.4 其他改进
| 特性 | 说明 |
|---|---|
| 部分快速DDL | ALTER TABLE ALGORITHM=INSTANT |
| 临时表空间 | InnoDB临时表使用共享的临时表空间ibtmp1 |
| 自动配置 | innodb_dedicated_server自动配置InnoDB内存参数 |
| UNDO表空间 | 默认创建2个UNDO表空间,不再使用系统表空间 |
| 重命名表空间 | 支持ALTER TABLESPACE ... RENAME TO |
总结
本文全面介绍了MySQL 8.0的新特性,帮助你顺利升级:
核心新特性:
-
账户与安全:
- 用户创建和授权必须分开执行
- 默认认证插件变为caching_sha2_password
- 支持密码历史管理和重复使用限制
-
索引增强:
- 隐藏索引:支持灰度发布和软删除
- 降序索引:真正支持DESC索引,优化排序性能
- 函数索引:支持表达式和JSON路径索引
-
CTE通用表表达式:
- 支持递归CTE
- 简化层级查询(如组织架构、树形结构)
-
窗口函数:
- 聚合窗口函数:SUM、AVG、COUNT等
- 专用窗口函数:ROW_NUMBER、RANK、LAG、LEAD等
-
原子DDL:
- DDL操作要么全部成功,要么全部失败
- 避免部分执行导致的数据不一致
-
InnoDB改进:
- 自增列持久化,解决重复问题
- 死锁检查可控
- 锁定语句支持NOWAIT和SKIP LOCKED
升级建议:
- MySQL 5.7已停止支持,建议尽快升级到8.0
- 升级前测试应用兼容性(特别是认证插件)
- 利用新特性优化查询性能(窗口函数、CTE、函数索引)
- 使用隐藏索引进行灰度测试
面试高频问题:
- MySQL 8.0有哪些新特性?(隐藏索引、窗口函数、CTE、原子DDL等)
- 隐藏索引有什么作用?(灰度发布、软删除)
- 什么是窗口函数?和普通聚合函数有什么区别?(每行都返回结果)
- 什么是原子DDL?有什么好处?(DDL操作原子性)
- MySQL 8.0默认认证插件是什么?(caching_sha2_password)
希望这篇文章能帮助你全面了解MySQL 8.0新特性!如果觉得有帮助,欢迎点赞、收藏、关注~
推荐标签:
- MySQL8
- 新特性
- 隐藏索引
- 窗口函数
- CTE
- 降序索引
- 原子DDL
- 面试