mysql 8.0 存储过程执行计划可复用,但条件更严苛:需sql文本完全一致、无用户变量、无非确定性函数、明确定义且实际满足deterministic、表结构与统计信息未变更;否则缓存失效导致每次调用重复init和权限检查。

MySQL 8.0 存储过程性能并不天然优于 5.7,实际中更常见的是变慢——尤其在未适配默认行为变更时。所谓“优于”只在特定调优后成立,核心差异不在存储过程本身,而在执行计划缓存、事务隔离、确定性校验等底层机制变化。
MySQL 8.0 存储过程执行计划缓存是否复用?
会复用,但条件比 5.7 更严苛。8.0 中存储过程内部的 SQL 语句仍可命中执行计划缓存(注意:不是已移除的 query cache),前提是:
- SQL 文本完全一致(含空格、大小写),不能含
@var用户变量或临时表 - 语句不调用非确定性函数(如
NOW()、RAND()、UUID()) - 过程定义中明确声明
DETERMINISTIC,且运行时未触发隐式非确定行为(例如内部用了@a := @a + 1) - 表结构、索引、统计信息未发生变更;否则缓存自动失效
常见错误现象:SHOW PROFILE 显示每次调用都经历大量 init 和 checking permissions 阶段,说明执行计划未被复用。
为什么显式设置 READ COMMITTED 能提升存储过程性能?
因为 MySQL 8.0 默认 transaction_isolation = 'REPEATABLE-READ',而 5.7 很多生产环境习惯设为 READ-COMMITTED。当存储过程内含 START TRANSACTION 但未指定级别时,会继承会话默认值。
在高并发更新场景下,REPEATABLE-READ 触发更重的 MVCC 版本链遍历,尤其是 SELECT ... FOR UPDATE 类语句延迟明显上升。实操建议:
- 在存储过程开头加
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; - 用
SELECT @@transaction_isolation;验证实际生效值,别只看配置文件 - 若业务强依赖可重复读语义,优先改用
SELECT ... LOCK IN SHARE MODE替代全表扫描式FOR UPDATE
DETERMINISTIC 标志为何在 8.0 中反而导致性能下降?
8.0 强化了对 DETERMINISTIC 的运行时校验:即使你写了该关键字,只要过程体中出现任何非确定性操作(如 NOW()、用户变量、子查询调用非确定函数),MySQL 就会在首次执行时将其标记为 NOT DETERMINISTIC,并禁用该语句的执行计划缓存复用。
这直接导致同一存储过程在 5.7 下耗时稳定,在 8.0 下每次波动大。排查方法:
- 执行
SHOW CREATE PROCEDURE proc_name;确认定义中是否真写了DETERMINISTIC - 避免用
@var传参,改用IN/OUT参数 - 时间类逻辑尽量用输入参数替代
NOW();随机值提前生成好作为IN参数传入
真正影响性能的不是“8.0 比 5.7 快”,而是 8.0 把过去被忽略的隐式开销显性化了:MVCC 成本、确定性校验、原子 DDL 同步等。不改代码只升级版本,大概率变慢;但针对性调整隔离级别、清理非确定操作、规范参数传递后,执行计划缓存复用率和稳定性才能真正提升。











