MySQL 8.0 存储过程没有更低的编译开销,首次执行开销通常更高;其执行计划复用条件比5.7更严苛,需SQL文本字节级一致、无用户变量、无非确定性函数、DETERMINISTIC声明与运行行为严格匹配,否则每次调用均触发完整init和权限检查。

MySQL 8.0 存储过程**没有更低的编译开销**——相反,它的首次执行开销通常更高,且更容易因隐式行为触发重复解析。
SHOW PROFILE 显示大量 init 和 checking permissions 阶段?说明执行计划没复用
这不是编译变快了,而是你误判了“编译”和“执行计划复用”的区别。8.0 中存储过程内部 SQL 的解析树和执行计划缓存复用条件比 5.7 更严苛,稍有不一致就会退回到全路径初始化流程:
-
SQL文本必须字节级一致(空格、大小写、换行都不能差) - 不能含
@var用户变量(哪怕只读) - 不能调用
NOW()、RAND()、UUID()等非确定性函数 - 过程定义中写了
DETERMINISTIC,但运行时用了@a := @a + 1这类隐式非确定操作,会导致首次执行后被标记为NOT DETERMINISTIC,后续所有调用都禁用缓存 - 表结构或统计信息变更(如
ANALYZE TABLE后),也会使已缓存计划失效
为什么 5.7 看起来“编译快”,而 8.0 总在重新 init?
5.7 对确定性校验宽松,很多带 @var 或 NOW() 的过程仍能复用执行计划;8.0 把过去被忽略的校验显性化了——它不是变慢了,而是把原本隐藏在后台的开销暴露出来:
- 每次调用都要做更严格的权限检查(尤其涉及
mysql系统库元数据访问时) - 事务隔离级别默认是
REPEATABLE-READ,若过程内含START TRANSACTION且未显式设级别,会触发更重的 MVCC 快照初始化 - 字符集从
utf8升级到utf8mb4_0900_ai_ci后,若字段定义未同步调整,可能引发隐式转换,导致索引失效 + 执行计划重建
如何让 8.0 存储过程真正复用执行计划?
关键不是“降低编译开销”,而是“满足复用条件”:
- 用
SHOW CREATE PROCEDURE proc_name检查是否真写了DETERMINISTIC,且过程体里没藏NOW()或用户变量 - 把时间逻辑改成
IN dt DATETIME参数传入,而非在过程里调NOW() - 把随机值提前生成好作为
IN参数传入,别在过程里调RAND() - 确认
SELECT @@transaction_isolation返回的是READ-COMMITTED(若业务允许),避免REPEATABLE-READ带来的 MVCC 初始化开销 - 升级后务必跑一次
ANALYZE TABLE,否则 Cost Model 估算失准,也可能导致计划频繁变更


















