在 Oracle 日常运维中,统计信息过期 、索引设计不合理是引发 SQL 性能暴跌最常见的两大元凶。很多时候 SQL 语句本身没有业务逻辑问题,但因优化器无法获取真实数据分布、索引匹配度差,会生成严重失真的执行计划,造成数据库 CPU、IO 飙升、业务接口超时。
本文整理生产环境两个真实经典优化案例,全程对业务表、索引做脱敏替换,完整还原故障现象、执行计划分析、根因定位、落地优化及长效固化全过程,适合运维、开发、DBA 参考学习。
案例一 自动统计收集窗口不合理引发执行计划跑偏
1. 故障现象
业务分页查询接口响应突然变慢,数据库后台负载升高。排查锁定一条高频分页 SQL,执行耗时飙升,逻辑读居高不下,整体业务吞吐量受到明显影响。
2. 问题脱敏 SQL
SQL_ID :2t45w000gxtvt
SELECT *
FROM (SELECT r.*, ROWNUM AS row_num
FROM (SELECT s.PRO_ID,
s.TOM_ID,
s.GATE_TODE,
s.PRO_NAME,
s.PRO_UNIT,
s.PRO_PRICERANGE,
s.PRO_TOTAL_SUPPLY,
s.PRO_TRANSPORTATION,
s.PRO_PRICE,
s.URL_TYPE
FROM BUSS.PRO_SEA_INFO_DETAIL s,
BUSS.PRO_EAR_REL g
WHERE s.TOM_ID = g.TOM_ID
AND g.TOM_ID = :1
AND g.ENCRYPT_FLAG = '0'
AND s.GROUP_ID = g.GROUP_ID
AND s.PHO_EXI_FLAG_TEAM IN ('1', '2')
AND s.PRO_ID <> :2
ORDER BY s.PRO_ID ASC) r)
WHERE row_num <= :3
绑定变量传入示例:
-
:1 = 682981062
-
:2 = 713586892
3. 原始低效执行计划
计划哈希值:1589909250
| Id | Operation | Name | A-Rows | A-Time | Buffers |
|---|---|---|---|---|---|
| 0 | SELECT STATEMENT | 50 | 00:00:00.12 | 16227 | |
| 1 | VIEW | 50 | 00:00:00.12 | 16227 | |
| 2 | COUNT | 2114 | 00:00:00.12 | 16227 | |
| 3 | VIEW | 2114 | 00:00:00.12 | 16227 | |
| 4 | NESTED LOOPS | 2114 | 00:00:00.11 | 16227 | |
| 5 | TABLE ACCESS BY INDEX ROWID | PRO_SEA_INFO_DETAIL | 5392 | 00:00:00.06 | 5433 |
| 6 | INDEX RANGE SCAN | IDX_PRO_SEARCH_01 | 5395 | 00:00:00.01 | 36 |
| 7 | INDEX RANGE SCAN | IDX_PRO_GROUP_05 | 2114 | 00:00:00.05 | 10794 |
谓词过滤关键条件
-
按指定 TOM_ID 过滤数据
-
筛选图片标识为 1/2 的数据
-
排除指定 PRO_ID
-
关联关系表匹配分组及加密标识
4. 基础信息排查
4.1 表统计信息状态
| 表名 | 统计信息状态 | 最后收集时间 |
|---|---|---|
| PRO_EAR_REL | 正常未过期 | 2020-03-13 05:08 |
| PRO_SEA_INFO_DETAIL | 已过期 | 2020-03-21 02:33 |
4.2 数据表体量
-
PRO_SEA_INFO_DETAIL:约 54.87GB 超大业务表
-
PRO_EAR_REL:仅 57MB 小配置表
4.3 表 DML 变更情况
查询数据增删改记录发现:
在周日晚间该大表发生大批量 INSERT/UPDATE/DELETE操作,数据分布发生剧烈变化,但统计信息未同步更新。
5. 根因深度定位
-
数据库自动统计收集窗口限制
数据库默认自动收集任务时间:
-
周一至周五:22:00 开始,持续 8 小时
-
周六:00:00 开始,仅持续 2 小时
-
周日无自动统计收集任务
-
-
故障时间节点
-
3 月 22 日(周日):大表批量 DML,数据分布巨变,无自动统计收集
-
3 月 23 日凌晨:优化器依赖过期老旧统计信息,错误评估行数与选择率,生成极差执行计划
-
直接表现:SQL 逻辑读暴增、耗时拉长,拖累整体数据库负载
-
6. 优化解决方案
临时应急
手动对超大表立即收集最新统计信息,刷新优化器数据分布认知:
exec dbms_stats.gather_table_stats('BUSINESS','PRO_SEA_INFO_DETAIL',cascade=>true,degree=>8);
长效根治
-
调整数据库自动统计任务窗口,补全周日收集时段,避免周末大表变更无统计刷新;
-
对高并发、大体量业务表,配置增量统计收集,降低收集耗时;
-
对核心稳定 SQL,采用SQL Profile/COE 脚本绑定最优执行计划,杜绝计划漂移;
-
监控表统计信息过期状态,纳入日常巡检告警。
案例二 索引设计不合理导致查询性能极差
1. 故障现象
某基础数据查询 SQL 执行耗时高达 5 秒以上,逻辑读近 38 万,资源消耗极大,频繁拖慢批量同步任务。
2. 问题脱敏 SQL
SQL_ID :9f7f63q4a6wqb
SELECT TOM_ID,
PRO_ID,
PIC_ID,
DISPLAY_ORDER,
STATUS,
HIST_FLAG
FROM BUSS.PRO_PEC_MAIN
WHERE (STATUS IN ('3', '4', '5') OR HIST_FLAG = '1')
AND SYNC_FLAG IN ('F', 'N');
3. 原始执行计划问题
计划哈希值:567836261
| Id | Operation | Name | E-Rows | A-Rows | Buffers | Time |
|---|---|---|---|---|---|---|
| 0 | SELECT STATEMENT | 136 | 387K | 00:00:05.52 | ||
| 1 | INLIST ITERATOR | 136 | 387K | 00:00:05.52 | ||
| 2 | TABLE ACCESS BY INDEX ROWID | PRO_PEC_MAIN | 4584K | 136 | 387K | 00:00:05.52 |
| 3 | INDEX RANGE SCAN | IDX_PIC_MAINTAIN_OLD | 5299K | 5582K | 43937 | 00:00:00.01 |
核心问题
优化器预估返回458 万行 ,实际仅返回136 行 ,预估行数严重失真;现有索引仅匹配单字段,无法适配OR多条件复合查询,导致大量无效索引扫描与回表。
4. 数据分布与索引排查
4.1 字段数据分布
对查询条件字段分组统计,发现数据倾斜严重:
大部分数据集中在少数状态值,符合条件的结果集极小,但索引无法精准过滤。
4.2 现有索引现状
表上已有索引仅为单字段 / 不合理联合索引,没有适配当前 SQL 查询条件的复合索引:
-
现有索引:单列状态、单列同步标识
-
缺失:
STATUS+SYNC_FLAG、HIST_FLAG+SYNC_FLAG适配联合索引
5. 优化落地
5.1 新建适配联合索引
-- 适配状态+同步标识查询
create index BUSS.IDX_STATUS_SYNC
on BUSS.PRO_PEC_MAIN (STATUS,SYNC_FLAG) tablespace IDX_TBS;
--适配历史标识+同步标识查询
create index BUSS.IDX_PIC_HIST_SYNC
on BUSS.PRO_PEC_MAIN (HIST_FLAG,SYNC_FLAG) tablespace IDX_TBS;
5.2 Hint 强制走新索引验证
创建索引后优化器未自动选择,通过 Hint 指定索引路径:
SELECT /*+ index(m IDX_STATUS_SYNC) index(m IDX_PIC_HIST_SYNC) */
TOM_ID,
PRO_ID,
PIC_ID,
DISPLAY_ORDER,
STATUS,
HIST_FLAG
FROM BUSS.PRO_PEC_MAIN m
WHERE (STATUS IN ('3', '4', '5') OR HIST_FLAG = '1')
AND SYNC_FLAG IN ('F', 'N');
5.3 优化后执行效果
-
执行耗时:5.52 秒 → 0.01 秒
-
逻辑读:387K → 仅 26
-
性能提升近万倍,完全满足业务实时查询需求
6. 长效固化方案
使用 COE 执行计划绑定脚本,将优化后的最优执行计划固化到数据库,避免后续统计信息变更、版本升级导致索引失效、计划回退。
总结:两大 SQL 性能问题运维启示
-
统计信息是执行计划的根基
超大表批量 DML 后极易出现统计过期,务必合理规划自动收集窗口,补齐周末空档,核心业务表建议增加手动兜底收集。
-
索引设计必须贴合业务 SQL
不能盲目建单列索引,针对
OR、多字段组合过滤场景,必须设计适配联合索引,遵循等值字段前置原则。 -
执行计划预估失真必排查两点
统计信息是否过期、索引是否匹配业务条件,90% 的慢 SQL 都能从这两点找到根因。
-
核心 SQL 务必固化执行计划
优化完成后通过 SQL Profile、COE 脚本绑定最优计划,防止后续环境变更引发性能回退。
-
日常运维建议将统计信息过期、TOP 慢 SQL、索引失效纳入常态化巡检,提前规避故障而非事后救火。