不是。mysql存储过程无传统编译缓存,alter procedure仅修改元数据;升级后变慢主因是优化器行为变化、统计信息陈旧或配置调整,须执行analyze table更新统计信息、对比explain计划、检查变量查询计划缓存问题。

MySQL 升级后存储过程变慢,是不是要 ALTER PROCEDURE 重新编译?
不是。MySQL 存储过程没有传统意义上的“编译缓存”,ALTER PROCEDURE 只是重写元数据,不会触发执行计划重建或优化器重评估。升级后性能下降,根本原因通常是优化器行为变化、统计信息陈旧或默认配置调整,而非“过程没重编译”。
升级后必须立刻更新表统计信息:用 ANALYZE TABLE 而非 OPTIMIZE TABLE
ANALYZE TABLE 会重新采样索引和数据分布,直接影响优化器对 JOIN 顺序、索引选择、临时表策略的判断——这对含复杂查询的存储过程尤为关键。而 OPTIMIZE TABLE 主要用于碎片整理,对执行计划无影响,还可能锁表。
- 对存储过程中频繁访问的表逐个执行:
ANALYZE TABLE orders, customers, order_items; - 避免全库扫描式操作(如
mysqlcheck --analyze),易引发长锁;优先覆盖高频表 - 如果使用 InnoDB,确认
innodb_stats_auto_recalc=ON(5.6.6+ 默认开启),但升级后首次仍需手动触发 - 注意:低版本(如 5.7)中
ANALYZE TABLE是阻塞操作;8.0+ 支持并发采样,但仍建议在低峰执行
检查并适配优化器开关与成本模型参数
MySQL 5.7 → 8.0 升级后,optimizer_switch 默认值变更(如 hash_join=on 启用)、use_stat_tables 行为调整、甚至直方图支持开启,都可能导致同一存储过程走完全不同执行路径。
- 对比升级前后实际执行计划:
EXPLAIN FORMAT=TREE(8.0)或EXPLAIN FORMAT=JSON(5.7+),重点关注join_execution和used_columns字段 - 临时关闭可疑特性验证影响,例如:
SET SESSION optimizer_switch='hash_join=off';再调用存储过程测试 - 若过程依赖精确行数估算,检查是否启用了直方图:
SELECT * FROM information_schema.COLUMN_STATISTICS WHERE schema_name='db' AND table_name='t';;有则确认histogram_type是否合理 - 避免全局修改
optimizer_switch,应在存储过程开头用SET SESSION局部控制,更安全
存储过程内嵌查询要防“参数化嗅探失效”
MySQL 不像 SQL Server 有参数化嗅探机制,存储过程中的查询若使用变量(如 WHERE status = p_status),优化器在首次调用时基于该变量值生成计划,并缓存复用——若后续传入高基数/低选择率值,就可能持续走错索引。
- 强制重生成计划:在关键查询前加
/*+ RECOMPILE */注释(8.0.22+ 支持) - 降级兼容方案:用
PREPARE + EXECUTE动态构造语句,绕过计划缓存(但注意 SQL 注入风险) - 最稳妥方式:拆分逻辑,将易变条件的查询独立成新存储过程,用不同名称隔离执行计划
- 验证是否命中此问题:查
performance_schema.events_statements_summary_by_digest,看同一DIGEST_TEXT对应的AVG_TIMER_WAIT是否波动极大
真正耗时的从来不是“重编译”这个动作,而是升级后优化器面对旧统计信息、旧习惯写法和新规则时的误判。重点盯住 ANALYZE TABLE 是否执行、EXPLAIN 结果是否突变、以及变量驱动查询是否被计划缓存绑架——这三处漏掉任意一个,补再多 ALTER PROCEDURE 都没用。











