暂无图片
暂无图片
5
暂无图片
暂无图片
暂无图片

偶发性-性能SQL排查-db file sequential read

原创 布衣 2025-09-01
519

背景

最近开发反馈有个任务偶尔性的执行变慢,平时都是10分钟左右完成,偶尔1小时完成。如果超过2小时的话可能就会影响业务后续进度,因此让我排查一下或优化一下SQL。

  • 查看任务执行日志如下:
select start_time 创建日期,end_time 结束日期, to_char(TRUNC(sysdate) + (end_time - start_time), 'HH24:MI:SS') 执行耗时 from summary_log l order by 1 desc;
  • 确实快的时候2-3分钟完成,慢的时候1小时+还没有跑完
    image.png
  • SQL 脱敏如下:
INSERT INTO T1 (......) SELECT ...... FROM T1 A LEFT JOIN (SELECT ...... FROM T2 WHERE CREATE_DATE >= to_date('2025-07-27','yyyy-mm-dd') AND CREATE_DATE < to_date('2025-07-28','yyyy-mm-dd') GROUP BY ACCT_ID) SUBQUERY ON SUBQUERY.ACCT_ID = A.ACCT_ID LEFT JOIN T2 B ON B.ACCT_ID = A.ACCT_ID WHERE A.CREATE_DATE >= to_date('2025-07-26','yyyy-mm-dd') AND A.CREATE_DATE < to_date('2025-07-27','yyyy-mm-dd') AND B.STATUS= 0;

排查分析

根据sql_id 生成执行计划报告

  • 手动执行脚本
@?/rdbms/admin/awrsqrpt.sql
  • 默认生成html格式
    image.png
  • 选择天数
    image.png
  • 选择Snap ID
    image.png
  • 填写SQL_id:4af6vusvps6cu
    image.png

查看20250726(00:10:43)、20250727(00:54:09)、20250728(00:12:42)、20250731(01:01:10)的AWR_SQL报告

  • awr_sql 性能瓶颈发现在IO
    image.png
  • TABLE ACCESS FULL 与 NDEX RANGE SCAN的执行结果都有快与慢的时候,因此分析与执行计划无关。
    image.png

生成ash报告

  • 手动执行脚本
@?/rdbms/admin/ashrpt.sql
  • 发现在执行慢的ash报告中,SQL引发的db file sequential read等待事件占比30-40%左右
    image.png
  • db file sequential read
    Oracle数据库中一种常见的I/O相关等待事件,表示数据库进程正在从数据文件中顺序读取数据块到SGA(系统全局区)中。遇到的案例:Insert 引起的 db file sequential read有细节介绍。
  • 查看引发此事件的对象
select o.OBJECT_NAME,h.event,h.sql_opname,h.sql_plan_operation,h.machine,h.SAMPLE_TIME from dba_hist_active_sess_history h join dba_objects o on o.OBJECT_ID=h.current_obj# where h.SAMPLE_TIME >= to_date('2025-08-07 10:30:00', 'yyyy-mm-dd hh24:mi:ss') and h.SAMPLE_TIME <= to_date('2025-08-07 11:30:00', 'yyyy-mm-dd hh24:mi:ss') AND h.sql_id='4af6vusvps6cu';

image.png

Insert操作引发db file sequential read

虽然insert操作本身主要是写入操作,但在以下情况下会引发db file sequential read等待事件:

1、索引维护开销

当表上有索引时,insert操作需要同时维护所有相关索引,这会导致:

  • 数据库需要查询索引块以确定新记录的插入位置;
  • 每次索引块查询都会产生单块读取,表现为db file sequential read;
  • 索引分裂(当索引块空间不足时)会产生额外的单块读取;

2、高并发insert场景

在高并发insert环境下:

  • 多个会话同时维护相同索引会导致索引块访问冲突;
  • 索引块可能频繁从磁盘读取到SGA,增加db file sequential read等待;

3、索引碎片问题

当索引存在严重碎片时:

  • 索引维护需要访问更多分散的索引块;
  • 增加单块读取的次数和等待时间;
  • 行迁移和行链接也会导致额外的单块读取;

模拟生产环境

  • 在测试环境对T1表进行历史数据恢复,然后保留1年内的基础数据,其它历史数据进行truncate partition update indexes 操作,使索引产生大量碎片。
表名 索引 实际大小GB 产生碎片后大小GB 碎片率
T1 IDX_T1_ID 12.01 40.01 70%
T1 IDX_T1_CUST 7.6 7.3 -
T1 SYS_C00722650 15.38 48.14 68%
  • 执行消耗对比:
性能指标 无碎片 有碎片
Elapsed 00:01:01.73 00:15:38.00
recursive calls 187 33
db block gets 6,103,959 3,407,341
consistent gets 1,311,473 818,618
physical reads 977,810 1,384,066
redo size 1,696,362,588 587,160,312
rows processed 644,921 644,921
  • 等待事件
    image.png

总结

根据以上模拟实验,基本可以肯定是因为碎片导致insert 产生的db file sequential read(单块读)从而引起SQL的偶发性变慢。

  • 碎片分析
    将生产表通过expdp/impdp操作导入到测试库中查询其索引大小,然后与生产对比大小
SELECT a.owner, b.table_name,b.INDEX_NAME, round(a.GB,2) GB FROM (SELECT OWNER, SEGMENT_NAME, TABLESPACE_NAME, (SUM(BYTES) / (1024 * 1024 * 1024)) AS GB FROM DBA_SEGMENTS GROUP BY OWNER, SEGMENT_NAME, TABLESPACE_NAME ) a left join ALL_INDEXES b on a.SEGMENT_NAME = b.INDEX_NAME where b.table_name IN ('T1') order by 2,3,4

image.png

  • 最终对涉及到的表进行索引重建完成碎片整理,后续继续观察执行效果。

欢迎赞赏支持或留言指正
image.png

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论