mysql 8.0存储过程变慢主因有四:事务隔离级别默认repeatable-read导致mvcc开销增大;deterministic标志因运行时非确定操作失效致执行计划缓存不可复用;原子ddl使drop/create变慢但更安全;sql_mode移除no_auto_create_user致grant报错。

存储过程执行变慢?先查 transaction_isolation 默认值
MySQL 8.0 存储过程在未显式指定事务隔离级别时,会继承会话默认值 REPEATABLE-READ;而很多 5.7 生产环境习惯性设为 READ-COMMITTED。这导致相同逻辑在 8.0 下触发更重的 MVCC 版本链遍历,尤其当过程内含 SELECT ... FOR UPDATE 时,延迟明显上升。
- 用
SELECT @@transaction_isolation;确认当前会话实际生效值,别只看配置文件 - 若过程开头有
BEGIN ... END+START TRANSACTION,务必加SET TRANSACTION ISOLATION LEVEL READ COMMITTED; - 如需可重复读语义,优先改用
SELECT ... LOCK IN SHARE MODE替代全表扫描式FOR UPDATE
DETERMINISTIC 标志反而让执行计划缓存失效
8.0 强化了对 DETERMINISTIC 的运行时校验:哪怕定义里写了该关键字,只要过程体中出现 NOW()、RAND()、用户变量(如 @a)或子查询调用非确定函数,MySQL 就会在首次执行时将其标记为 NOT DETERMINISTIC,并禁用该语句的执行计划缓存复用。
- 执行
SHOW CREATE PROCEDURE proc_name;确认定义中是否真写了DETERMINISTIC - 避免在 SP 中用
@var传参,改用IN/OUT参数 - 时间类逻辑尽量用输入参数代替
NOW();随机值提前生成好作为IN参数传入
原子 DDL 导致 DROP/CREATE PROCEDURE 变慢但更安全
8.0 将 DROP PROCEDURE/CREATE PROCEDURE 归入原子 DDL,整个操作要写入数据字典事务日志、同步 binlog、刷盘后才返回成功。相比 5.7 的“先删后建”,单次部署耗时可能增加 3–10 倍(尤其在磁盘 I/O 压力大或 binlog_format=ROW 时)。
- 这不是性能倒退,而是保障一致性:5.7 中若
DROP成功但CREATE失败,过程就永久丢失;8.0 要么全成功,要么回滚到原状 - 上线前预估好变更窗口,避免在高峰期执行大批量存储过程重建
- 若使用自动化部署工具(如 Liquibase、Flyway),确认其已适配 8.0 原子 DDL 行为
sql_mode 移除 NO_AUTO_CREATE_USER 导致 GRANT 报错
8.0 完全移除了 NO_AUTO_CREATE_USER,且默认禁止 GRANT 隐式创建账号。如果你的存储过程或初始化脚本里包含类似 GRANT SELECT ON db.* TO 'user'@'%'; 且该用户不存在,就会直接报错:Variable 'sql_mode' can't be set to the value of 'NO_AUTO_CREATE_USER' 或 Operation CREATE USER failed。
- 升级前检查所有涉及
GRANT的 SQL,确保对应用户已存在,或显式加上CREATE USER - 备份恢复时若含旧版
mysqldump输出(含NO_AUTO_CREATE_USER设置),需手动清理该选项再导入 - 应用连接池配置中若硬编码了
sql_mode,也要同步剔除已移除项
真正影响兼容性的不是语法层面的断裂,而是 8.0 把过去被忽略的隐式行为显性化了:事务隔离成本、确定性校验、原子性保证、权限模型收紧——这些点不逐个对齐,光靠“能跑通”就上线,后续问题只会越来越隐蔽。











