vault backup: 2026-11-07 16:33:44

This commit is contained in:
cheney
2026-11-07 16:33:55 +08:00
commit 7015312702
1208 changed files with 132432 additions and 0 deletions
@@ -0,0 +1,213 @@
![MySQL 5.7 和 8.0 到底差在哪?升完才知道不止一点点](https://pic1.zhimg.com/v2-1136e188e21439036b1d0fd84ce1d84d_720w.jpg?source=7e7ef6e2&needBackground=1)
> 项目跑了五年的 MySQL 5.7,某天下午决定升到 8.0。迁移脚本顺利跑完,服务重启,然后——连接报错、查询行为异常、某个 GROUP BY 语句直接执行失败。排查到凌晨两点,才把所有问题逐一定位清楚。这些坑本可以提前避开。
## **前言**
MySQL 5.7 已于 **2023年10月正式 EOL**,不再有安全补丁,继续用的风险只会越来越高。但"要不要升"从来不是问题,问题是"升之前要搞清楚哪些东西会变"。本文把两个版本的核心差异逐一拆开,踩过的坑全写在里面。
## **一、默认字符集:从 latin1 到 utf8mb4**
这是升级后最容易被忽视、也最容易踩坑的地方。
|版本|默认字符集|默认排序规则|
|---|---|---|
|MySQL 5.7|latin1|latin1_swedish_ci|
|MySQL 8.0|utf8mb4|utf8mb4_0900_ai_ci|
MySQL 5.7 的默认字符集是 `latin1`,大量中文项目在建库时如果没有手动指定 `utf8mb4`,就会踩表情符号存储失败、中文乱码等问题。8.0 默认就是 `utf8mb4`,这个历史遗留坑算是填上了。
但要注意:`utf8mb4_0900_ai_ci` 的排序规则和 5.7 常用的 `utf8mb4_general_ci` **行为不完全一致**,迁移时如果直接 dump/restore,可能导致排序结果、索引行为出现细微差异。建表时建议显式指定,别依赖默认值。
## **二、认证插件变了,连接可能直接报错**
这是 8.0 升级后反馈最多的"坑"之一。
MySQL 8.0 将默认认证插件从 `mysql_native_password` 改为 `caching_sha2_password`。
```text
-- 查看当前用户的认证插件
SELECT user, host, plugin FROM mysql.user;
```
旧版驱动(比如某些 PHP、Java 早期 JDBC 驱动、Navicat 老版本)不支持 `caching_sha2_password`,连接时会直接报错:
```text
Authentication plugin 'caching_sha2_password' cannot be loaded
```
**临时解法**是把特定账户改回旧插件:
```text
ALTER USER 'your_user'@'%' IDENTIFIED WITH mysql_native_password BY 'your_password';
```
但长期来看应该升级驱动。安全性上,`caching_sha2_password` 比 `mysql_native_password` 更强,是正确方向。
> ⚠️ 注意:MySQL 8.4 开始已彻底废弃 `mysql_native_password`,8.0 用户如果在过渡期,要提前把驱动升到位。
## **三、SQL 能力大幅增强**
这是 8.0 最值得升级的理由之一,尤其对写复杂查询的开发来说。
### **3.1 窗口函数(Window Functions)**
5.7 没有窗口函数,要实现排名、滑动求和这类需求,只能靠变量模拟,写法丑且性能差。8.0 原生支持:
```text
-- 按部门分组,对每个员工计算薪资排名
SELECT
name,
dept,
salary,
RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS salary_rank
FROM employees;
```
类似的还有 `ROW_NUMBER()`、`DENSE_RANK()`、`LAG()`、`LEAD()`、`SUM() OVER()` 等,这些在数据分析、报表场景里极其常用。
### **3.2 公共表表达式(CTE)**
支持 `WITH` 语法,递归查询终于可以写了:
```text
-- 递归查询组织架构
WITH RECURSIVE org AS (
SELECT id, name, parent_id, 1 AS depth
FROM department WHERE parent_id IS NULL
UNION ALL
SELECT d.id, d.name, d.parent_id, o.depth + 1
FROM department d
JOIN org o ON d.parent_id = o.id
)
SELECT * FROM org;
```
5.7 要实现同样逻辑,要么存储过程,要么应用层递归,代码量和维护成本都更高。
### **3.3 JSON 能力全面增强**
5.7 引入了 JSON 类型,但操作函数偏基础。8.0 大幅扩展了 JSON 函数库,新增了:
- `JSON_TABLE()`:将 JSON 数组展开成关系表,可直接 JOIN 查询
- `->>`:简化的 JSON 路径提取操作符
- 对 JSON 索引的优化支持更完善
对于半结构化数据存 MySQL 的场景,8.0 的 JSON 能力明显更成熟。
## **四、性能:8.0 整体更强,但有细节**
官方 Benchmark 数据显示,MySQL 8.0 在高并发读写场景下比 5.7 有明显提升,尤其是:
- **InnoDB 读写锁优化**:减少了 redo log 的锁竞争,高并发写入吞吐量更高
- **Hash Join**:8.0.18 起支持 Hash Join,某些等值 JOIN 场景性能提升显著
- **隐式排序消除**:优化器对 GROUP BY 不再默认排序,在不需要有序结果时更快
不过也有反例:部分复杂查询在 8.0 上因为优化器策略变化,执行计划反而比 5.7 差。升级前建议用线上慢查询日志做一轮回归测试,重点关注执行计划是否有变化。
```text
-- 对比执行计划
EXPLAIN FORMAT=JSON SELECT ...;
```
## **五、数据字典:从文件迁移到 InnoDB**
5.7 的数据字典部分存在 `.frm` 文件中,部分在 `information_schema` 里,管理分散,数据库文件目录下一堆 `.frm` 文件是常见风景。
8.0 将数据字典完全迁移到 InnoDB 系统表,不再有 `.frm` 文件。好处是:
- DDL 操作支持**原子性**(Atomic DDL):`CREATE TABLE` 失败不会留下半截文件
- `information_schema` 查询性能提升
- 数据库文件目录更干净
## **六、不可见索引(Invisible Index)**
运维场景里很实用的一个功能。
```text
-- 将索引设为不可见(优化器不会使用,但索引仍然维护)
ALTER TABLE orders ALTER INDEX idx_status INVISIBLE;
-- 验证没有这个索引时的查询性能,没问题再删除
ALTER TABLE orders DROP INDEX idx_status;
```
5.7 想验证"删掉某个索引会不会影响查询",只能真删,发现有问题再重建,代价很高。8.0 可以先设置为不可见,观察一段时间没问题再正式删除,给了一个反悔的机会。
## **七、角色管理(Role-Based Access Control)**
5.7 的权限管理是直接给用户 GRANT,账号一多就乱。8.0 引入了 Role:
```text
-- 创建角色并授权
CREATE ROLE 'app_read';
GRANT SELECT ON mydb.* TO 'app_read';
-- 把角色赋给用户
GRANT 'app_read' TO 'alice'@'%';
```
对于多人协作、权限分层管理的团队来说,这个功能能省不少重复操作。
## **八、两个版本的主要差异汇总**
|维度|MySQL 5.7|MySQL 8.0|
|---|---|---|
|官方维护状态|❌ 已停止(2023.10 EOL)|✅ 活跃维护中|
|默认字符集|latin1|utf8mb4|
|默认认证插件|mysql_native_password|caching_sha2_password|
|窗口函数|❌ 不支持|✅ 支持|
|CTE / 递归查询|❌ 不支持|✅ 支持|
|Hash Join|❌ 不支持|✅ 支持(8.0.18+)|
|原子 DDL|❌|✅|
|不可见索引|❌|✅|
|RBAC 角色管理|❌|✅|
|数据字典存储|.frm 文件 + InnoDB|全部 InnoDB|
|JSON 能力|基础|增强(JSON_TABLE 等)|
|高并发写入性能|基准|整体更优|
## **九、怎么选?**
### **新项目:直接上 8.0**
没有历史包袱,没有理由选 5.7。8.0 的 SQL 能力、性能、安全性全面领先,且是官方当前维护的版本。选稳定的 GA 版本(比如 8.0.36+),不要追最新的 8.4 或 9.x,坑还没被社区踩完。
### **存量项目:评估后计划迁移**
核心建议是**不要拖**,5.7 已经没有安全补丁了,跑在生产上的风险会越来越高。
迁移步骤建议:
```text
1. 升级驱动和 ORM 版本,确认兼容 caching_sha2_password
2. 在测试环境搭 8.0,导入生产数据跑回归测试
3. 重点检查:字符集、排序规则、执行计划变化、触发器/存储过程
4. 用 pt-upgrade 或 MySQL Shell 的升级检查工具做兼容性扫描
5. 灰度切流,监控错误日志和慢查询
```
### **短期无法迁移的存量项目**
如果因为各种原因(比如旧系统改不动、第三方软件限制)暂时无法升级:
- 确保数据库不直接暴露在公网
- 定期审计账号权限,关掉不用的账号
- 把升级计划排进 roadmap,设一个明确的截止时间
## **十、常见升级踩坑速查**
|问题|原因|解决方案|
|---|---|---|
|连接报认证错误|驱动不支持 caching_sha2_password|升级驱动 或 改用 mysql_native_password|
|查询结果排序变了|排序规则从 general_ci 变为 0900_ai_ci|建表时显式指定排序规则|
|GROUP BY 报错|8.0 对非聚合字段的检查更严格|修复 SQL,显式使用聚合函数或 ANY_VALUE()|
|存储过程/函数行为异常|SQL mode 默认值变化|检查 sql_mode,按需调整|
|执行计划变差|优化器策略调整|用 HINT 或 optimizer_switch 强制执行计划|
## **总结**
MySQL 8.0 不只是版本号的升级,从 SQL 能力到底层架构都有实质性改进。5.7 的 EOL 也意味着继续使用的技术债会越来越重。
对于新项目,8.0 是唯一合理的选择。对于存量项目,建议把迁移提上日程,越早处理,成本越低。