首页/数据/SQL 速查/执行计划突变排查思路
性能与执行计划72 条

执行计划突变排查思路

同一条 SQL 变慢但语句没改:先看计划是否变化,再查统计信息、数据分布与参数化因素。

SQL 速查数据更新于 2026-10-13

同一条 SQL 突然变慢

语句一个字没改,执行时间却从几十毫秒涨到几秒,绝大多数不是数据库「随机抽风」,而是执行计划变了。代价模型依赖统计信息、数据分布、可用索引与传入参数,任何一项变化都可能让优化器改选另一条路径。排查顺序通常是从估算与实际的差距开始,再依次检查统计信息新鲜度、数据倾斜、索引变更,最后才考虑参数化带来的计划分化。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
首要证据分析模式输出的估算行数与实际行数对比
常见原因统计信息过期、数据分布变化、索引增减、参数取值差异
临时手段强制索引或提示语句用于验证方向与应急恢复
根治方向更新统计、调整索引结构、必要时固定语句形态

典型使用场景

  • 线上接口耗时突然上升,需要确认是否与计划变化相关
  • 数据导入或大促后,报表类语句开始明显变慢
  • 新索引上线后,另一批语句反而变慢(代价模型被改变)
  • 预编译语句在不同参数下表现差异巨大,需要区分计划类型
  • 建立回归比对机制:保留关键语句的计划快照,变更前后对比

排查步骤示例

排查步骤示例
-- 第一步:看估算与实际行数的差距,落差大说明统计信息或分布有问题
EXPLAIN ANALYZE SELECT ... ;

-- 第二步:MySQL 侧更新统计信息后复看
ANALYZE TABLE orders;

-- 第三步:PostgreSQL 侧验证参数差异导致的计划分化
EXPLAIN (ANALYZE) SELECT * FROM orders WHERE user_id = 100;  -- 选择性高的参数
EXPLAIN (ANALYZE) SELECT * FROM orders WHERE user_id = 1;    -- 选择性低的参数

-- 预编译语句可能复用不适合当前参数的缓存计划
SHOW plan_cache_mode;            -- 查看当前策略
-- 需要时可按会话临时切换为强制自定义计划,验证是否由缓存计划引起

-- 第四步:必要时用强制索引验证方向,确认后再改语句或索引结构

常见原因对照

原因现象处理方向
统计信息过期估算与实际差距大重新采样统计信息
数据分布变化含倾斜取值的数据变多提高统计精度或改写语句形态
索引增减旧语句选了新路径复核索引组合,避免功能重叠
参数取值极端同一语句快慢因参数而异区分计划类型或改写为等值加范围
缓存计划失真预编译语句长期走坏计划调整计划缓存策略
分析模式会真实执行语句,评估前先确认它属于读操作,或把语句包在事务里执行后立刻回滚。生产环境的执行代价要提前估算。
把关键语句的计划与耗时定期归档,是判断「计划突变」的前提。没有历史快照时,只能靠猜测,排查周期会被拉长很多。

易错点

  • 把计划突变当偶发问题,用重启或临时扩容应付,根因仍在,不久后再次发生
  • 只在测试库复现:测试数据分布与参数都与生产不同,计划根本不一样,结论无效
  • 直接用强制索引或提示语句长期上线:绕过代价模型,数据变化后可能更糟,只适合应急与验证
  • 忽略预编译语句的计划缓存:参数取值跨度大时,缓存计划对一部分参数严重不合适
  • 新增索引后不复核已有语句:代价模型改变,原本正常的语句可能改走更差的路径

数据来源与参考

  • MySQL 8.0 Reference Manual · Optimizing Queries with EXPLAIN
  • PostgreSQL Documentation §14.1 Using EXPLAIN
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌