Files
Knowledge/1 使用/数据库/MySQL 5.7 和 8.0 到底差在哪?.md

213 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
![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 是唯一合理的选择。对于存量项目,建议把迁移提上日程,越早处理,成本越低。