执行计划一夜之间变了?别查代码了,是统计信息在"说谎"

简介: 昨天还跑得飞快的SQL,今天突然慢到怀疑人生。代码没改、索引没动、数据量也没暴涨——罪魁祸首是统计信息过期导致的执行计划突变。本文从优化器原理出发,深度解析为什么执行计划会"背叛"你,以及如何建立统计信息监控机制,让慢SQL扼杀在摇篮里。

大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!

有个经典的"凌晨惊魂"场景:某条核心SQL跑了半年都没问题,每天几十万次执行,响应时间稳定在5毫秒以内。某天凌晨三点,监控告警疯狂弹窗——这条SQL突然飙到5秒,CPU打满,整个系统雪崩。

DBA赶到现场,第一反应是看代码有没有人改。没有。看索引有没有人删。没有。看数据量有没有暴涨。也没有。

最后查下来,原因让人无语:统计信息过期了。数据库优化器拿着一份"过时的情报",给这条SQL选了一条错误的执行计划。

今天把执行计划突变的底层原理、排查手段和预防机制,一次讲清楚。


一、先搞懂几个概念

执行计划(Execution Plan):数据库执行一条SQL的具体步骤。先走哪个索引、先JOIN哪张表、用什么JOIN方式(Nested Loop、Hash Join、Merge Join),这些决策组合起来就是执行计划。

优化器(Optimizer):数据库里的"决策引擎",负责为每条SQL选择最优的执行计划。它不跑SQL,只"猜"哪种执行方式最快。

统计信息(Statistics):优化器做决策的依据。包括表的总行数、每列的数据分布(最大值、最小值、NULL占比、直方图)、索引的选择性(不同值的数量)等。本质上就是优化器眼中的"数据库快照"。

基数估计(Cardinality Estimation):优化器预估每一步会返回多少行数据。预估准了,执行计划就优;预估偏了,就可能选错索引、选错JOIN顺序。

CBO(Cost-Based Optimizer):基于成本的优化器。优化器根据统计信息计算每种执行计划的"成本"(CPU消耗、IO次数、内存占用),选成本最低的那个。

理解了这些概念,就能回答一个核心问题:为什么执行计划会突然变?


二、执行计划为什么会"背叛"你

统计信息过期:优化器拿到的是"过期情报"

这是最常见的原因。统计信息不是实时更新的,大多数数据库是定期收集或手动触发。

假设你有一张订单表,平时100万行,统计信息也是按这个量级收集的。某天大促,数据量涨到500万,但统计信息还没更新。优化器依然认为表里只有100万行——于是选择了全表扫描(因为它觉得100万行全表扫比走索引快)。实际上500万行全表扫描直接卡死。

统计信息 ≠ 实时数据,它是一份"延迟的快照"。

数据倾斜:平均值骗了优化器

即使统计信息是新的,也可能因为数据分布不均匀而误导优化器。

比如一个订单表的status列,99%的数据是COMPLETED,1%是PENDING。如果统计信息只记录了平均分布(没有收集直方图),优化器会认为每个状态的占比差不多。当你查询status = 'COMPLETED'时,优化器预估返回1000行(总行数10万的1/100),实际返回99000行——走索引反而比全表扫慢几十倍。

索引变化:新增索引不一定是好事

开发同学看到慢SQL,第一反应是加索引。加完索引后统计信息更新,优化器重新评估所有可用索引,可能选出一个更差的执行计划。

加索引 ≠ SQL变快,它只是给优化器多了一个选择,而这个选择可能是错的。

参数变更:看似无关的配置调整

  • optimizer_modeALL_ROWS 改为 FIRST_ROWS
  • optimizer_features_enable 版本升级后行为变化
  • statistics_levelTYPICAL 改为 BASIC(停止收集部分统计信息)

这些参数调整不会立刻生效,但下一次硬解析时,优化器的决策逻辑可能完全改变。


三、执行计划突变的排查步骤

第一步:确认是不是执行计划变了

-- Oracle
SELECT * FROM v$sql_plan WHERE sql_id = 'your_sql_id';

-- MySQL (8.0+)
EXPLAIN FORMAT=TREE SELECT ...;

-- PostgreSQL
EXPLAIN (ANALYZE, BUFFERS) SELECT ...;

-- 对比历史执行计划
-- Oracle: DBMS_XPLAN.DISPLAY_AWR('your_sql_id')

重点对比:访问路径(全表扫 vs 索引扫描)、JOIN顺序、JOIN方式、预估行数 vs 实际行数

第二步:检查统计信息是否过期

-- Oracle:查看表的统计信息收集时间
SELECT table_name, last_analyzed, num_rows, blocks
FROM user_tables
WHERE table_name = 'YOUR_TABLE';

-- MySQL:查看InnoDB表统计信息
SHOW TABLE STATUS LIKE 'your_table';

-- PostgreSQL:查看统计信息
SELECT last_analyze, last_autoanalyze, n_live_tup, n_dead_tup
FROM pg_stat_user_tables
WHERE relname = 'your_table';

如果last_analyzed是几天甚至几周前,而这段时间数据变化超过10%,基本可以判定统计信息过期。

第三步:对比预估行数和实际行数

这是判断优化器是否"误判"的关键指标。

-- 执行SQL时开启实际执行统计
-- Oracle: EXPLAIN PLAN FOR ... 然后 SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
-- MySQL: EXPLAIN ANALYZE SELECT ...;
-- PostgreSQL: EXPLAIN ANALYZE SELECT ...;

如果某一步的预估行数(estimated rows)和实际行数(actual rows)相差10倍以上,说明基数估计严重失真,执行计划很可能选错了。

第四步:检查是否有绑定变量窥探问题

绑定变量第一次执行时,优化器会"窥探"变量值来生成执行计划。后续执行直接复用这个计划,即使变量值的数据分布差异很大。

比如第一次传的是status = 'PENDING'(只有100行),优化器选了索引扫描。后面传的是status = 'COMPLETED'(99000行),还是走索引——但全表扫描反而更快。


四、预防执行计划突变的4种手段

手段一:合理设置统计信息收集策略

不要完全依赖自动收集,根据业务特点定制:

策略 适用场景 收集频率
自动收集 + 默认阈值 数据变化平稳的普通表 系统自动触发
手动定时收集 数据批量导入/删除的表 每天凌晨或批量操作后
锁定统计信息 历史归档表(数据不变化) 收集一次后锁定
收集直方图 数据分布严重倾斜的列 按需收集
-- Oracle: 手动收集统计信息(含直方图)
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA', 'TABLE_NAME',
  method_opt => 'FOR COLUMNS SIZE AUTO skewed_column');

-- MySQL: 手动分析表
ANALYZE TABLE your_table;

-- PostgreSQL: 手动分析
ANALYZE your_table;

手段二:使用执行计划基线(Plan Baseline)

Oracle提供了SQL Plan Management(SPM),可以把"好的执行计划"锁定下来,即使统计信息变化也不让优化器切换到更差的计划。

-- Oracle: 创建执行计划基线
DECLARE
  l_plans_loaded  PLS_INTEGER;
BEGIN
  l_plans_loaded := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(
    sql_id => 'your_sql_id');
END;

金仓数据库也提供了类似的执行计划管理能力。通过DBMS_SPM兼容包,可以将经过验证的优秀执行计划固定下来,避免因统计信息变化导致的性能波动。同时支持执行计划演化(evolve),在确认新计划更优后才自动切换。

手段三:SQL Profile / Outline

SQL Profile是优化器的"纠正器"。当发现某条SQL的执行计划不理想时,可以创建一个SQL Profile,告诉优化器"这条SQL按这个方式执行"。

-- Oracle: 使用SQL TUNING ADVISOR
DECLARE
  l_tuning_task VARCHAR2(30);
BEGIN
  l_tuning_task := DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_id => 'your_sql_id');
  DBMS_SQLTUNE.EXECUTE_TUNING_TASK(l_tuning_task);
  DBMS_SQLTUNE.ACCEPT_SQL_PROFILE(task_name => l_tuning_task);
END;

手段四:监控统计信息变化

建立监控机制,在统计信息过期前主动预警:

-- 找出统计信息超过7天未更新的表
SELECT table_name, last_analyzed,
  ROUND((SYSDATE - last_analyzed), 1) as days_since_analyze
FROM user_tables
WHERE last_analyzed < SYSDATE - 7
ORDER BY last_analyzed;

建议在监控系统中加入以下告警项:

  • 核心表统计信息超过X天未更新
  • 单表数据变化量超过上次统计的10%
  • 执行计划发生变更(对比AWR报告)

五、总结

执行计划突变的本质,是优化器拿着一份过时的地图,给你指了一条错误的路。

代码没改、索引没动,SQL突然变慢——不要急着翻代码,先查统计信息。

排查执行计划问题,按这个顺序来:

  1. 对比执行计划:确认是不是执行计划变了,不是SQL本身的问题
  2. 检查统计信息:last_analyzed多久了?数据变化量超过10%了吗?
  3. 预估 vs 实际:基数估计偏差超过10倍,优化器就"失明"了
  4. 绑定变量:第一次执行的变量值,可能不适合后续的变量值

预防胜于治疗:统计信息收集策略 + 执行计划基线 + 变化监控,三管齐下,让慢SQL扼杀在摇篮里。


小耶在手,SQL不愁。

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~

相关文章
|
8天前
|
人工智能 JSON 安全
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
阿里云AI安全产品联动防御Fastjson攻击
2188 12
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
|
8天前
|
云安全 人工智能 安全
|
8天前
|
人工智能 自然语言处理 数据挖掘
Qwen3.8-Max-Preview深度全解析:2.4万亿参数旗舰MoE模型+Token Plan限时优惠完整落地指南
2026年7月,全新旗舰级混合专家大模型Qwen3.8-Max-Preview正式开放抢先体验,作为通义千问Qwen3系列规格最高、综合推理能力顶尖的新一代模型,该模型总参数量达到2.4万亿(2.4T),是当前线上可调用的原生多模态旗舰模型,综合推理水准对标海外顶级Fable 5模型,在复杂工程开发、长文档深度分析、多步骤智能体自治、跨境多语言创作、海量数据挖掘五大高难度业务场景实现跨越式性能提升。
989 1
|
10天前
|
人工智能
Qwen3.8抢先体验!正式版即将发布并开源!
千问Qwen3.8即将开源,参数达2.4T,进化速度以“天”计,实力媲美Fable 5。预览版Qwen3.8-Max已上线阿里Token Plan等平台,限时优惠:日间Credits低至1折,夜间更优,个人/团队版月付仅35元起!
992 44
|
8天前
|
人工智能 自然语言处理 数据挖掘
最新版通义千问(Qwen3.8-Max-Preview)功能介绍
2026年,通义千问正式推出全新旗舰级大模型 **Qwen3.8-Max-Preview 预览版**,作为首款突破万亿参数规格的新一代基座模型,该模型总参数量达到**2.4万亿**,采用全新迭代的MoE混合专家架构,综合推理性能、长文本处理、多模态理解、复杂任务规划能力全面超越前代Qwen3.7-Max版本,整体实力跻身全球第一梯队,可对标海外顶级旗舰模型,是当前面向复杂工程开发、多智能体协同、超长文档解析、专业办公自动化场景的最优国产基座模型。
1004 0
|
7天前
|
自然语言处理 测试技术 API
通义千问Qwen3.8-Max-Preview全功能解析:2.4万亿参数旗舰模型深度使用指南
在大模型技术持续迭代的当下,通义千问推出的Qwen3.8-Max-Preview作为新一代旗舰预览版模型,凭借2.4万亿参数的超大规模、多模态融合能力与全场景适配特性,成为开发者与企业用户探索AI应用的核心工具。该模型采用稀疏混合专家(MoE)架构,是通义千问首个突破万亿参数的多模态模型,可同时处理文本、图像、视频与文档等多种数据形态,在全栈代码开发、复杂逻辑推理、长文档分析与多智能体协作等场景实现跨越式升级。本文将全面拆解Qwen3.8-Max-Preview的核心功能,详解API调用流程与配置方法,覆盖多场景实战技巧,帮助用户快速掌握这款旗舰模型的使用方法,充分释放其性能潜力。
488 1
|
10天前
|
人工智能 自然语言处理 数据挖掘
Qwen3.8-Max 预览版全解析:2.4 万亿参数旗舰模型,Token Plan 限时优惠指南
Qwen3.8-Max-Preview是通义千问Qwen3系列旗舰MoE大模型,参数达2.4万亿,综合推理能力居行业第一梯队。支持思考/快速双模式,擅长大模型五大高难场景。现于阿里云百炼Token Plan、Qoder及QoderWork上线体验,个人版低至39元/月。在阿里云百炼官网:https://t.aliyun.com/U/fPVHqY 免费领取千万Tokens
690 1
Qwen3.8-Max 预览版全解析:2.4 万亿参数旗舰模型,Token Plan 限时优惠指南

热门文章

最新文章