暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

Oracle 19c数据库SQL问题定位和分析:卡慢SQL排查-基础篇【Oracle数据库分享--0x22】

Acdante 2026-05-13
30

Oracle 问题定位和分析:卡慢SQL排查
从等待事件到执行计划,基础起步-看这一篇就够了

    半夜告警响不停,SQL跑得慢吞吞
    数据库里千行泪,皆因等待苦争奔
    锁住资源不肯放,IO瓶颈把人坑
    且看老夫七板斧,定位元凶破迷津
    ——深夜DBA有感-Acdante

    凌晨3点,监控大屏突然变红:"数据库响应时间 > 30秒"!你从被窝里爬出来,手忙脚乱地敲着键盘,心里一万只草泥马奔腾而过。打开V$SESSION一看,一堆会话在那儿"等待"着,也不知道在等什么。最近又被再次翻出来的麻园诗人的泸沽湖洗脑了。这神奇的旋律虽然早几年就在听,但也是属于小众歌曲,这段时间,又火了一次,神奇的旋律,放在文章开头,有兴趣可以听听哈。

    这场景,每个DBA都经历过。说实话,80%的性能问题都是SQL惹的祸。今天我就把压箱底的SQL排查功夫全部传授给你,从等待事件到执行计划,从绑定变量到统计信息,保证你看完就能定位那些"卡死"你的慢SQL。现在也有很多这样的性能检测平台和各类工具,如聚好看团队的 DBDoctor如白鳝老师的性能分析平台等,都可以非常直观的探测到各类性能问题。本文多个好用的 SQL 来源于黄廷忠老师的分享,他的个人主页:www.htz.pw以及他的公众号:大家也可以关注一下。对了以下脚本,均为真实实战 SQL,可运行。当然简单看 SQL 状态和当前运行 SQL,还有一个最最简单的方式:如果有条件使用 Oracle自己的官方工具-SQLDeveloper,直接链接后,就有各种 SQL 监视器可以直观可视化。黄老师的SQL对于 11g是直接可用,分享内的SQL文件都是原版文件。我文章内的基本都适配19c了,已经更新适配调整过,也整理成txt了。有需要可以后台回复“SQL”即可获取。

    IT民工的龙马人生

    黄廷忠,公众号:IT民工的龙马人生SQL优化实战:标量子查询改写外连接的真实案例

    📌 本文目标:理解等待事件本质 + 掌握6大类排查SQL + 建立系统化SQL诊断思路。

    01.等待事件——数据库的"体温计"

    很多人问我:"SQL跑得慢,到底慢在哪儿了?"我的回答是:看等待事件!

    Oracle的等待事件,就是数据库的"体温计"。正常情况下,体温36.5度;发烧了,38度。等待事件也是一样,正常运行的数据库,等待很少;出问题了,等待事件就会告诉你"哪儿疼"。

    等待事件分类——先分清敌我

    Oracle的等待事件成千上万,但可以分为几大类,这里只是列出几个常见的和本人用分析的几个大类等待事件,大家有补充可以交流讨论:

    等待类别
    常见事件
    问题定位
    User I/O
    db file sequential read
    db file scattered read
    索引缺失?统计信息过期?
    Concurrency
    buffer busy waits
    gc buffer busy
    热块争用?并发太高?
    Application
    enq: TX - row lock
    enq: TM - contention
    锁等待?外键无索引?
    System I/O
    log file sync
    log file parallel write
    日志写慢?磁盘IO问题?
    Network
    SQL*Net message from client
    SQL*Net more data to client
    网络延迟?批次太大?
    Configuration
    log buffer space
    free buffer waits
    参数配置不合理?

    核心视图:V$SESSION_WAIT 和 V$SESSION

    V$SESSION_WAIT
     是Oracle最常用的实时等待视图,每一秒都在刷新,记录着当前正在等待的会话。V$SESSION
     则包含了会话的完整信息,包括当前SQL、等待事件等。可以说查会话、查性能、查 SQL 多半是离不开这两个视图的,也是实时性能分析最常用的两个视图。

    ⚠️ 注意:从Oracle 10g开始,V$SESSION_WAIT的大部分信息已经合并到V$SESSION中,所以直接查V$SESSION就行,别再费劲查两个视图了!

    02.从等待事件定位问题SQL——六步定位法

    知道了等待事件分类,接下来就是实战。我总结了六步定位法,从宏观到微观,逐步缩小范围。

    03.排查实战SQL——拿走就能用

    公众号 SQL 格式有点问题复制进来,需要完整脚本我整理成txt了,有需要关注后发送“SQL”获取

    第一类:TOP等待事件分析

    1.1 数据库TOP等待事件(累计)

    输出示例:可以看看我这个库等待事件能看出什么明细,哈哈。

    1.2 等待类统计(按类别汇总)

    输出示例:

    第二类:当前活跃会话分析

    2.1 当前等待中的会话(按等待事件分组)

    输出示例:

    2.2 活跃会话详情(包含SQL_ID和等待信息)

    输出示例:

    2.3 [RAC] 全局活跃会话(RAC环境)

    输出示例:

    第三类:IO等待专项分析(db file相关)

    db file sequential read = 索引/单块读
    db file scattered read = 全表扫描/多块读

    3.1 IO等待会话(重点关注db file类事件)

    输出示例:暂无

    3.2 热块分析(buffer busy waits)

    暂无

    04.SQL性能分析——V$SQL和V$SQLSTATS

    找到SQL_ID后,下一步就是分析SQL性能。V$SQL和V$SQLSTATS是最常用的SQL性能视图。

    4.1 关键字段解读

    字段名
    含义
    关注重点
    ELAPSED_TIME
    总执行时间(微秒)
    除以EXECUTIONS=单次执行时间
    CPU_TIME
    CPU时间(微秒)
    CPU占比=CPU/ELAPSED
    BUFFER_GETS
    逻辑读次数
    除以ROWS=每行逻辑读
    DISK_READS
    物理读次数
    高=可能缺索引
    ROWS_PROCESSED
    处理行数
    与fetch结合看
    EXECUTIONS
    执行次数
    0=未执行/刚刚入库
    FETCHES
    取出行数
    SELECT才有值
    SORTS
    排序次数
    高=可能缺排序空间
    PLAN_HASH_VALUE
    执行计划哈希
    不同=执行计划变了

    4.2 SQL性能统计查询(基于V$SQLSTATS)

    输出示例:

    4.3 指定SQL_ID的性能指标(sql_stat_by_sqlid核心逻辑)

    📎 脚本参考来源:黄廷忠(htz),http://www.htz.pw,做了 19c适配

    输出示例:

    05.绑定变量窥探——还原真实SQL

    找到慢SQL后,你看到的SQL文本可能是这样的:

    SELECT * FROM orders WHERE customer_id = :1 AND status = :2

    什么鬼?:1
     和 :2
     是啥值?这就是绑定变量的"锅"。Oracle为了复用执行计划,把具体值替换成了占位符。

    问题来了:有时候执行计划选错了,恰恰就是因为这个绑定变量的"特殊值"触发了绑定变量窥探,导致走了错误的执行计划!

    5.1 查看绑定变量值(V$SQL_BIND_CAPTURE)

    根据SQL_ID获取绑定变量值

    -- 核心查询:从V$SQL_BIND_CAPTURE获取绑定变量 

    ⚠️ 注意:V$SQL_BIND_CAPTURE默认15分钟采样一次,如果SQL刚执行完,可能采样不到!这时候要看V$SQL_MONITOR。

    5.2 从V$SQL_MONITOR获取实时绑定变量

    -- 从V$SQL_MONITOR的BINDS_XML获取绑定值(针对特定会话) 

    绑定变量窥探的坑:Oracle在第一次执行时,会根据实际传入的值来决定执行计划。如果第一次传入的值是"极端值"(比如MIN或MAX),后续即使传正常值,也可能沿用那个极端的执行计划!

    06.执行计划分析——定位性能瓶颈

    执行计划是SQL优化的"地图"。看不懂执行计划,就像开车没有导航,只能瞎开。

    6.1 获取执行计划的方法

    方法1:DBMS_XPLAN.DISPLAY_CURSOR(从库缓存)

    -- 查看指定SQL的执行计划(需要SQL_ID) SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&SQL_ID', NULL, 'ALLSTATS LAST'));

    方法2:DBMS_XPLAN.DISPLAY_AWR(AWR历史)

    -- 查看AWR中保存的执行计划(需要SQL_ID) 
    SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('&SQL_ID'));

    方法3:查看当前会话的SQL执行计划

    -- 查看当前SESSION正在执行的SQL计划 
    SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));

    6.2 SQL Monitor报告

    SQL Monitor是Oracle企业版的"神器",能看到实时执行的详细信息,包括各步骤的等待时间、IO统计等。

    查看SQL Monitor报告(文本格式)

    -- 查看SQL Monitor统计信息 

    查看SQL执行进度(实时监控)

    -- 长时间运行的SQL执行进度 

    6.3 ASH执行计划统计

    ASH(Active Session History)记录了活动会话的历史快照,可以帮我们分析执行计划各步骤在过去一段时间的等待情况。

    -- ASH执行计划统计(最近1小时的采样统计) 

    07.大杀器:sql10综合诊断脚本

    说了这么多SQL,有没有一个脚本能一键生成完整的诊断报告?有的!这就是sql10,来自Oracle圈著名DBA黄廷忠(网名"认真就输")。

    📎 sql10.sql 功能清单:
    ✅ 完整SQL文本(含绑定变量替换)
    ✅ 执行计划(从库缓存/AWR)
    ✅ ASH执行计划统计
    ✅ SQL Monitor报告
    ✅ V$SQLSTATS/V$SQL统计信息
    ✅ 表信息、索引信息
    ✅ 列统计信息(含MIN/MAX值)
    ✅ 分区信息(支持CDB)

    sql10脚本核心功能展示

    📎 脚本来源:黄廷忠(htz),http://www.htz.pw

    sql10使用方式(简化版)

    -- sql10.sql 使用方式 
    -- 方式1:传入SQL_ID @sql10.sql SQL_ID  
    -- 方式2:传入SQL_ID和优化器环境 @sql10.sql SQL_ID OPTIMIZER_ENV_ID  
    -- 方式3:开启列MIN/MAX值收集(检测谓词越界) @sql10.sql SQL_ID '' '' '' '' '' '' _TABLE_COL_VALUE

    sql_stat_by_sqlid(sql10子模块)——SQL统计信息

    -- sql_stat_by_sqlid.sql 
    核心查询逻辑 -- 从V$SQLSTATS获取性能指标

    sql_fulltext_by_sqlid(sql10子模块)——绑定变量替换

    -- sql_fulltext_by_sqlid.sql 
    核心逻辑 -- 从V$SQL_BIND_CAPTURE获取绑定变量 

    08.谓词越界与统计信息——容易被忽视的坑

    很多SQL跑着跑着突然变慢了,排查半天发现是谓词越界问题。

    什么是谓词越界?

    假设有个表 orders
    ,按 order_date
     建了索引。

    • 表的订单日期范围:2020-01-01 ~ 2024-01-01
    • 统计信息记录的MAX值:2024-01-01
    • 某天新插入了一批订单,日期:2024-06-15
    • 但是统计信息还没更新!

    这时候如果有个SQL:WHERE order_date > '2024-06-01'

    Oracle以为最多只有1天的数据(因为MAX是2024-01-01),可能选择索引扫描;
    实际上有半年的数据!结果就是——索引扫描反而更慢!

    8.1 查看列统计信息(含MIN/MAX)

    -- 查看表的列统计信息 

    8.2 查看列MIN/MAX值(数值类型)

    -- 从RAW类型转换获取实际MIN/MAX值 

    8.3 sql10的列统计信息收集(_TABLE_COL_VALUE参数)

    8.4 统计信息过时检测

    -- 检测表统计信息是否过期(19c 安全稳定版)

    -- 统计信息过期检查 + 安全的表增长估算(19c 适配)


    ⚠️ 统计信息过期警告:
    - 建议生产环境设置自动统计信息收集(默认窗口)
    - 大批量数据变更后(>10%行数变化)应手动收集统计信息
    - 使用 DBMS_STATS.GATHER_TABLE_STATS
     收集
    - 关键表可使用 CASCADE=>TRUE
     同时收集索引统计

    09.索引缺失与低效诊断

    索引是SQL优化的"万金油",但索引缺失或低效也是性能问题的常见原因。

    9.1 查看表的索引信息

    -- 查看表的索引

    9.2 查看索引列

    -- 查看索引的列 

    9.3 未建索引的外键(容易导致锁等待)

    -- 查找未建索引的外键列(父表DELETE时会锁住子表) 

    10.排查思路总结——六步定位法完整版

    好了,所有SQL都介绍完了,最后来一张完整的大图,帮助你建立系统化的排查思维:

    常见问题的快速判断

    等待事件
    可能原因
    排查方向
    db file seq read
    索引扫描单块读
    检查索引效率、是否回表多
    db file scat read
    全表扫描/索引快速全扫
    加索引、改SQL写法
    buffer busy waits
    热块争用
    优化数据分布、加索引减少TX锁
    enq: TX row lock
    行锁争用
    检查长事务、加索引减少锁范围
    log file sync
    日志写等待
    减少COMMIT频率、提高IO性能
    gc buffer busy
    [RAC] 全局缓存争用
    优化访问分布、热表分区
      SQL排查路漫漫,等待事件是明灯
      执行计划细分析,绑定变量见真情
      统计信息若过时,优化器也会发疯
      六步定位走天下,从此不怕慢SQL
      待到山花烂漫时,告警不再扰美梦
      ——DBA修行之路,Acdante作

      总结

      SQL性能问题排查的核心是从等待事件到SQL文本,从执行计划到统计信息的全链路分析。

      遇到慢SQL,记住六步定位法:

      查等待 → 找会话 → 分析性能 → 执行计划 → 还原SQL → 定位根因

      善用sql10等综合工具,结合本文的排查SQL,你也能成为SQL优化的"老中医"。

      📎 本文引用脚本说明基于hzt老师的脚本,做了 Oracle 19c的适配:

      sql_fulltext_by_sqlid.sql sql_fulltext_mem_by_sqlid.sql 

      / sql_stat_by_sqlid.sql / sql10.sql

      作者:黄廷忠(htz),http://www.htz.pw

      公众号:IT民工的龙马人生

      也欢迎关注我的主页:https://acdante.com和公众号:


      📌 关注公众号 Acdante,获取更多Oracle/MySQL技术干货~

      本文SQL脚本基于Oracle 19c验证,适用于单机及RAC环境,需要脚本,公众号后台回复“SQL”获取

      历史 Oracle文章合辑:

      Oracle生产级别备份脚本分享——逻辑备份和物理备份(expdp&RMAN)【Oracle数据库分享--0x01】

      Oracle数据加密技术演进与实践指南从10g到26ai的安全之道【Oracle数据库分享--0x02】

      Oracle数据库表空间与数据文件实战指南【Oracle数据库分享--0x03】

      Oracle ADG单机部署实战指南【Oracle数据库分享--0x04】

      Oracle DataGuard搭建信息收集清单和ADG自动化部署脚本(单机版本)免费开放【Oracle数据库分享--0x05】

      Oracle表空间使用率自动检测与智能扩容实战——Shell脚本监控告警及自动扩展数据文件与ASM磁盘组管理基础知识【Oracle数据库分享--0x06】

      Oracle数据库监听机制深度解析-Listener解密【Oracle数据库分享--0x07】
      Oracle19c-最新补丁19.30别着急更新有BUG已被抛弃-最新19.31已发布【Oracle技术分享-0x08】
      Oracle数据库等级保护(三级)安全配置实战指南-用户密码策略、审计和Linux系统账户安全配置实战操作【Oracle数据库分享--0x09
      Oracle数据快速恢复与还原实战指南:闪回功能与expdp逻辑备份【Oracle数据库分享--0x10】
      Oracle数据库日志体系-诊断和排查问题第一步-找到故障表现以及如何联动排查实战从11g-26ai【Oracle数据库分享--0x11】
      Oracle数据库节前巡检脚本分享——基础Shell巡检实践&自动化DB巡检系统分享【Oracle数据库分享--0x12】
      Oracle ADG故障处理指南ORA-01111:数据文件名未知的紧急恢复实战【Oracle数据库分享--0x13】
      Oracle RAC 三节点集群在线替换 ASM 磁盘组底层存储实战【Oracle数据库分享--0x14】
      Oracle容灾平台引发的思考-Acdante四层云原生容灾平台架构构思【架构构思分享--0x1】

      Oracle 26ai数据库架构体系结构与新特性浅显分享【Oracle数据库分享--0x15】

      Oracle 8i 迁移到11g-exp/imp 实战记录引发的六大数据库迁移方式深度对比分享【Oracle数据库分享--0x16】
      RAC性能分析 —— gc buffer busy acquire 等待事件深度解析【Oracle数据库分享--0x17】
      Oracle数据库+RHCS双机热备高可用架构和实施方案技术分享【Oracle数据库分享--0x18】
      Linux平台Oracle数据库磁盘运维实战手册从磁盘识别到ASM在线扩容,一文打尽日常运维痛点【Oracle数据库分享--0x19】
      关于数据库巡检那些事AI 赋能下的综合数据库巡检平台-DBCheck深度解析和分享【Oracle数据库分享--0x19】

      Oracle 19c数据库锁机制与排查实战和基础原理解析【Oracle数据库分享--0x21】

      文章转载自Acdante,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论