![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 是唯一合理的选择。对于存量项目,建议把迁移提上日程,越早处理,成本越低。