mysql 8.0 存储过程性能不天然优于5.7,常见变慢主因是执行计划缓存复用条件更严、事务隔离级别默认更重、原子ddl开销增大及deterministic校验失败导致缓存失效。

MySQL 8.0 存储过程性能并不天然优于 5.7,实际中更常见的是变慢——尤其在未适配默认行为变更时。所谓“改进”只在针对性调优后成立,核心差异不在语法或结构,而在底层执行机制的收紧与重构。
为什么SHOW PROFILE显示每次调用都卡在init和checking permissions?
这是执行计划缓存未复用的典型信号。MySQL 8.0 对存储过程中 SQL 语句的执行计划复用条件比 5.7 更严苛:
- SQL 文本必须完全一致(空格、大小写、换行都不能差)
- 不能含
@var用户变量,也不能引用临时表 - 不能调用
NOW()、RAND()、UUID()等非确定性函数 - 即使声明了
DETERMINISTIC,只要运行时触发隐式非确定行为(如@a := @a + 1),首次执行后就会被标记为NOT DETERMINISTIC,缓存直接失效 - 表结构、索引或统计信息任一变更,也会导致缓存自动丢弃
排查方法:执行 SHOW CREATE PROCEDURE proc_name;,确认是否真写了 DETERMINISTIC,再检查过程体里有没有偷偷用 @ 变量或时间函数。
为什么加了START TRANSACTION反而更慢?
MySQL 8.0 默认 transaction_isolation = 'REPEATABLE-READ',而很多 5.7 生产环境习惯设为 READ-COMMITTED。当存储过程内显式开启事务但未指定级别时,会继承会话默认值。
在高并发更新场景下,REPEATABLE-READ 触发更重的 MVCC 版本链遍历,尤其是 SELECT ... FOR UPDATE 类语句延迟明显上升。
实操建议:
- 在存储过程开头加
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; - 用
SELECT @@transaction_isolation;验证当前会话实际生效值,别只看配置文件 - 若业务强依赖可重复读语义,优先改用
SELECT ... LOCK IN SHARE MODE替代全表扫描式FOR UPDATE
为什么DROP+CREATE存储过程耗时暴涨?
MySQL 8.0 将 DROP PROCEDURE/CREATE PROCEDURE 归入原子 DDL,整个操作要写入数据字典事务日志、同步 binlog、刷盘后才返回成功。相比 5.7 的“先删后建”两步操作,单次部署耗时可能增加 3–10 倍(尤其磁盘 I/O 压力大或 binlog_format=ROW 时)。
这不是性能倒退,而是保障一致性:5.7 中若 DROP 成功但 CREATE 失败,过程就永久丢失;8.0 要么全成功,要么回滚到原状。
实操建议:
- 批量更新多个存储过程时,不要逐个
DROP+CREATE,改用CREATE OR REPLACE PROCEDURE(8.0.19+支持) - 上线前预估 DDL 时间,避免在高峰期执行
为什么DETERMINISTIC标志反而拖慢性能?
MySQL 8.0 强化了对 DETERMINISTIC 的运行时校验:即使你写了该关键字,只要过程体中出现任何非确定性操作(如 NOW()、用户变量、子查询调用非确定函数),MySQL 就会在首次执行时将其标记为 NOT DETERMINISTIC,并禁用该语句的执行计划缓存。
这直接导致同一存储过程在 5.7 下耗时稳定,在 8.0 下每次波动大。
关键规避点:
- 避免用
@var传参,改用IN/OUT参数 - 时间类逻辑尽量用输入参数替代
NOW() - 随机值提前生成好作为
IN参数传入,而非在 SP 内调用RAND()
真正影响性能的不是“有没有 DETERMINISTIC”,而是“有没有让 MySQL 相信它是确定的”。一旦校验失败,缓存失效,每次都要重新解析、权限检查、生成执行计划——这才是抖动根源。











