BUSS 业务系统SQL优化案例整理

在 Oracle 日常运维中,统计信息过期索引设计不合理是引发 SQL 性能暴跌最常见的两大元凶。很多时候 SQL 语句本身没有业务逻辑问题,但因优化器无法获取真实数据分布、索引匹配度差,会生成严重失真的执行计划,造成数据库 CPU、IO 飙升、业务接口超时。

本文整理生产环境两个真实经典优化案例,全程对业务表、索引做脱敏替换,完整还原故障现象、执行计划分析、根因定位、落地优化及长效固化全过程,适合运维、开发、DBA 参考学习。


案例一 自动统计收集窗口不合理引发执行计划跑偏

1. 故障现象

业务分页查询接口响应突然变慢,数据库后台负载升高。排查锁定一条高频分页 SQL,执行耗时飙升,逻辑读居高不下,整体业务吞吐量受到明显影响。

2. 问题脱敏 SQL

SQL_ID2t45w000gxtvt

复制代码
 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

谓词过滤关键条件

  1. 按指定 TOM_ID 过滤数据

  2. 筛选图片标识为 1/2 的数据

  3. 排除指定 PRO_ID

  4. 关联关系表匹配分组及加密标识

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. 根因深度定位

  1. 数据库自动统计收集窗口限制

    数据库默认自动收集任务时间:

    • 周一至周五:22:00 开始,持续 8 小时

    • 周六:00:00 开始,仅持续 2 小时

    • 周日无自动统计收集任务

  2. 故障时间节点

    • 3 月 22 日(周日):大表批量 DML,数据分布巨变,无自动统计收集

    • 3 月 23 日凌晨:优化器依赖过期老旧统计信息,错误评估行数与选择率,生成极差执行计划

    • 直接表现:SQL 逻辑读暴增、耗时拉长,拖累整体数据库负载

6. 优化解决方案

临时应急

手动对超大表立即收集最新统计信息,刷新优化器数据分布认知:

复制代码
exec dbms_stats.gather_table_stats('BUSINESS','PRO_SEA_INFO_DETAIL',cascade=>true,degree=>8);

长效根治

  1. 调整数据库自动统计任务窗口,补全周日收集时段,避免周末大表变更无统计刷新;

  2. 对高并发、大体量业务表,配置增量统计收集,降低收集耗时;

  3. 对核心稳定 SQL,采用SQL Profile/COE 脚本绑定最优执行计划,杜绝计划漂移;

  4. 监控表统计信息过期状态,纳入日常巡检告警。


案例二 索引设计不合理导致查询性能极差

1. 故障现象

某基础数据查询 SQL 执行耗时高达 5 秒以上,逻辑读近 38 万,资源消耗极大,频繁拖慢批量同步任务。

2. 问题脱敏 SQL

SQL_ID9f7f63q4a6wqb

复制代码
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_FLAGHIST_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 性能问题运维启示

  1. 统计信息是执行计划的根基

    超大表批量 DML 后极易出现统计过期,务必合理规划自动收集窗口,补齐周末空档,核心业务表建议增加手动兜底收集。

  2. 索引设计必须贴合业务 SQL

    不能盲目建单列索引,针对OR、多字段组合过滤场景,必须设计适配联合索引,遵循等值字段前置原则。

  3. 执行计划预估失真必排查两点

    统计信息是否过期、索引是否匹配业务条件,90% 的慢 SQL 都能从这两点找到根因。

  4. 核心 SQL 务必固化执行计划

    优化完成后通过 SQL Profile、COE 脚本绑定最优计划,防止后续环境变更引发性能回退。

  5. 日常运维建议将统计信息过期、TOP 慢 SQL、索引失效纳入常态化巡检,提前规避故障而非事后救火。

相关推荐
正在走向自律9 天前
标量子查询消除:数据库优化器的一场“等价变戏法”
数据库·sql 优化·金仓数据库·数据库性能调优·标量子查询·数据库优化器
青云交1 年前
大数据新视界 -- Hive 数据倾斜实战案例分析(2 - 16 - 6)
大数据·hive·数据分析·解决方案·数据倾斜·电商平台·实战案例·sql 优化