news 2026/10/15 5:04:15

Oracle卡顿排查:从告警日志、等待事件到系统日志的完整路径

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Oracle卡顿排查:从告警日志、等待事件到系统日志的完整路径

“系统又卡了”这句话,几乎是每个Oracle DBA的午夜梦魇。接手一个“oracle排查卡顿相关日志”的工单,最怕的不是问题复杂,而是面对一堆毫无头绪的日志不知道从哪里下手。这篇内容就是写给正在跟卡顿问题搏斗的运维、开发和架构同学的,我会从真实的排查视角出发,讲清楚告警日志、监听日志、系统统计信息和操作系统日志各自的定位,以及一套可以直接落地复用的分析顺序。读完你会发现,卡顿排查其实是有章法的。

1. 先别急着查日志,先把“卡顿”的定义说清楚

接到报障电话,我建议你第一句话先别问“日志在哪”,而是耐着性子问清楚:是所有业务都卡,还是某一个页面/某一条SQL卡?是一直卡,还是每隔一段时间卡几分钟?这三个问题决定了你后续排查完全不同的方向。

我自己踩过不少弯路。有一回某业务方半夜打电话说“库里锁死了”,我冲进机房一路查v$lock、杀会话,忙活半小时,最后发现人家说的“卡”只是他们自己应用网关超时,数据库压根没收到几个请求。所以拿到“卡顿”两个字,先别急着当技术问题处理,它可能只是应用侧感知异常,也可能真的来自数据库内部争用。

从技术角度看,Oracle里的卡顿通常能拆成三类:

卡顿类型典型表现大概率相关模块
全库型卡顿所有应用、所有会话都变慢日志切换、归档堵塞、共享池问题、I/O子系统故障
单会话型卡顿只有某个模块或某条SQL慢SQL执行计划劣化、行锁/表锁争用、绑定变量窥探
周期性尖刺每隔固定时间抖一下Job调度集中、日志切换周期、统计信息自动收集、检查点

把这个分类记在脑子里,再看日志就有方向了。日志的作用从来不是第一排查手段,而是用来验证你的猜测、补齐时间线的证据。

另外要特别提醒:Oracle官方给出的诊断路径里,数据库的告警日志只是入口,真正要把“为什么慢”钉死,必须结合动态性能视图(v$视图)、AWR/ASH报告和操作系统层的证据链。这也是后面几章我要展开的内容。

2. 告警日志:数据库主动留下的“案发现场”

2.1 告警日志在哪,翻天覆地找不到不如用adrci

数据库的alert日志(告警日志)就像服务器的“黑匣子”,数据库内部发生的严重错误、内部错误、死锁、表空间相关报错都会记在这里。从11g之后,告警日志被纳入ADR(Automatic Diagnostic Repository)体系,路径通常是:

$ORACLE_BASE/diag/rdbms/{db_unique_name}/{SID}/trace/alert_{SID}.log

如果你不想一层层翻目录,直接在命令行用adrci最省事:

adrci> show alert -tail 200

加-tail是只看末尾200行,适合快速确认最近有没有新错误。如果数据库还活着但卡得不行,先扫一遍alert日志里有没有ORA-00600、ORA-07445这种内部错误;如果数据库根本连不上,那alert日志最后几行往往就写着数据库为什么起不来。

2.2 日志切换失败导致的“全库卡死”识别

我遇到过的全库卡顿,有相当比例根因是归档日志写不进去。alert日志里反复出现这类信息:

ORA-00313: unable to open archived log '/u01/arch/xxx_12345.arc' ORA-00312: online log 1 thread 1: '/u01/oradata/redo01.log'

这种情况下,所有需要提交的事务都会卡在日志写入环节。你去看会话等待,会看到大量log file switch (archiving needed)或archiver stuck,整个库就像被按了暂停键。

排查顺序是这样:先确认归档目录空间是否打满df -h,再看归档进程状态archive log list,最后在v$archive_dest_status里看归档目标是不是失效了。如果归档盘满了,把空间清理出来,数据库通常几秒内就能恢复“呼吸”。

2.3 别忽略checkpoint not complete这类“温柔”的停顿

还有一种卡顿不像ORA-00313那样报错明显,而是alert日志里反复刷这样的信息:

Thread 1 cannot allocate new log, sequence 12345 Checkpoint not complete

这意味着日志切换时,DBWR还没把脏块写完,LGWR只能原地等待。表现就是:每隔几分钟,数据库准时抖一次,每次抖几秒到几十秒,业务时好时坏。

针对这种问题,光看alert日志不够,还要配合两个视图:

-- 查看日志切换频率与大小 select to_char(first_time, 'yyyy-mm-dd hh24:mi') day, count(*) cnt, round(sum(blocks*block_size)/1024/1024) mb from v$log_history group by to_char(first_time, 'yyyy-mm-dd hh24:mi') order by 1 desc; -- 查看DBWR是否频繁等待 select event, total_waits, time_waited/100 time_sec from v$system_event where event like '%checkpoint%' or event like '%log file parallel write%';

如果redo日志切换非常频繁(比如每3到5分钟就切一次),通常是redo日志组太小、业务DML过于密集,或者频繁commit但没有批量提交。针对这种场景,加大redo日志文件、调整checkpoint时机,往往比反复优化SQL更见效。

2.4 死锁记录ORA-00060:日志里的“业务冲突实锤”

如果卡顿伴随“某个操作报ORA-00060”,alert日志里会留下完整死锁图:

ORA-00060: Deadlock detected. More info in file /u01/diag/.../trace/xxxx_ora_1234.trc

跟踪文件里会详细列出两个会话各自持有的锁、等待的锁、涉及的SQL语句。我见过很多所谓的“数据库卡死了”,本质是应用层两个模块更新同一张表的顺序不一致:A先update表1再update表2,B先update表2再update表1,高并发下交叉等待,直接形成环形等待。

这类问题的修复通常不在数据库侧,而是在业务侧统一加锁顺序,或者走事务队列。作为DBA,你能做的就是把死锁跟踪文件里锁对象、SQL文本拉出来,交给开发优化逻辑顺序。

3. 监听日志与跟踪文件:连接异常的另一条线索链

3.1 连不上库、连接极慢,盯紧listener.log

很多卡顿其实发生在“连接建立”这个环节,而不是SQL执行环节。客户端一发起连接就卡住,或是应用报ORA-12520、ORA-12516,这种时候要看监听日志:

$ORACLE_BASE/diag/tnslsnr/{hostname}/listener/trace/listener.log

监听日志里每个连接请求都会记录客户端IP、端口、请求的Service Name、处理结果。如果短时间涌入大量请求,日志会哗啦啦地刷;如果进程数被占满,就会看到TNS-12520: TNS:listener could not find available handler。

判断连接慢的逻辑:如果连接请求之间时间戳间隔正常,只是单次建立连接耗时很久,问题通常在网络链路或DNS解析;如果同一时刻连接请求堆积成山,多半是应用连接池配置过小、被夯住了。

有个很实用的检查动作:在客户端机器上执行

tnsping 数据库服务名

如果tnsping每次往返都超过几十毫秒且不稳定,那基本可以甩锅给网络了,数据库侧日志再翻也翻不出花来。Windows平台还可以用sqlplus username/password@tns别名观察“连接到服务器”和“已连接”之间的耗时,粗略定位是哪一段慢。

3.2 用10046跟踪文件把一个会话“解剖”开

有时问题不在连接,而在某个具体会话内部。比如业务反馈“点保存按钮要转十秒”,但AWR里看不出所以然,因为单条SQL本身并不慢。这时最好的工具是SQL trace(10046事件)。

alter session set max_dump_file_size = unlimited; alter session set events '10046 trace name context forever, level 12'; -- 执行让业务复现一段慢操作 alter session set events '10046 trace name context off';

生成的trace文件会记录每个操作的等待事件、CPU消耗、物理读、逻辑读、解析时间。我处理过一个“报表导出卡顿”案例,SQL执行计划完全正常,但trace文件里全是log file sync等待,一查代码,原来是导出一行数据就commit一次,几千行数据提交了几千次,大量时间浪费在日志同步上。

掌握这个工具之后,“数据库卡顿”就能被拆成“解析慢、执行慢、等待资源慢”三种,定位精度完全不一样。

4. 日志之外,真正的高频排查路径是等待事件

4.1 卡顿当下抓现场:v$session和ASH是比日志更快的第一现场

如果卡顿正在发生,别等日志慢慢刷,直接执行下面这条SQL就能看到全场会话的等待状态:

select sid, sql_id, event, blocking_session, seconds_in_wait, wait_class, module from v$session where wait_class != 'Idle' and status = 'ACTIVE' order by seconds_in_wait desc;

重点看两个字段:EVENT是当前会话在等什么,BLOCKING_SESSION是被谁堵住了。如果BLOCKING_SESSION非空,顺着这个会话往上追,就能找到锁的源头。

如果卡顿是几分钟前发生的,你已经错过了当下现场,那就查ASH(Active Session History):

select to_char(sample_time, 'hh24:mi') sample_minute, event, count(*) cnt from v$active_session_history where sample_time > sysdate - 1/24 group by to_char(sample_time, 'hh24:mi'), event order by 1;

ASH是数据库自动保留的会话级采样历史,相当于把过去一段时间每个会话“在做什么”记录了下来。哪怕是事后排查,也能还原出卡顿那一刻所有会话的聚合行为。

4.2 I/O类等待:卡顿的“重灾区”

从等待事件分类来看,最容易造成严重卡顿的几类等待有:

等待事件含义常见根因
db file sequential read单块随机读慢存储I/O延迟高、冷热数据分布差、索引失效
db file scattered read多块全表扫描缺索引、坏计划、疯狂全表扫
direct path read/write直接路径读写并行度太高、临时表空间压力大
log file syncredo落盘慢频繁提交、存储写入慢、redo日志争用
enq: TX - row lock contention行锁争用高并发更新同一行、未提交事务锁表
library cache lock共享池游标争用硬解析风暴、存储过程失效重编译

怎么判断是不是存储问题?看平均等待时间。比如db file sequential read总等待时间很长、平均单次等待超过十几毫秒,就要怀疑存储链路;如果只是某一条SQL引起的等待次数很多,平均等待本身不高,那问题更可能在SQL设计。

我排过的一个典型场景:某生产库每天下午三点整点卡顿,等待事件集中在direct path write temp,顺着时间线一查,正好赶上某报表Job并行度设置为8的排序操作,海量临时数据涌向临时表空间,把I/O打满。把并行度调小,问题立刻消停。这种问题,你在alert日志里永远看不到,但等待事件会告诉你一切。

4.3 锁等待:从日志到阻塞链路的“顺藤摸瓜”

库卡住,最常见的另一个元凶是行锁、表锁或系统锁等待。查当前阻塞链路比较实用的SQL是:

select sid, blocking_session, event, wait_class from v$session where blocking_session is not null order by sid;

假设查出来SID 100被SID 88阻塞,而88本身又在等待另一个会话,那就是一条阻塞链。继续递归下去,直到最后那个event不是锁等待、而是SQL*Net message from client的会话,那就是一个“打开事务但什么都没干,手里攥着锁不放”的应用端未提交事务。把这个会话信息甩给业务开发,让他们检查代码里是不是忘了commit或者事务超时设太长。

别指望alert日志能帮你揪出这种锁问题,它只会偶尔打印一条ORA-00060。真正的现场在v$lock、v$session和DBA_BLOCKERS这些视图里。

5. 跨界排查:OS、存储和网络日志的配合使用

5.1 数据库日志正常,不代表系统没病:操作系统日志不能少

有一个特别容易进死胡同的场景:alert日志干干净净,AWR报告看起来也还行,但系统就是慢。这时候我强烈建议你把排查范围扩大到数据库之外。

先看操作系统层的三项指标:

# CPU与负载 sar -u 1 5 # 内存与换页 sar -r 1 5 # I/O设备的svctm、await、util sar -d 1 5

%wa过高,说明CPU在等待I/O,对应的是存储慢;pgpgin/pgpgout频繁大数值,说明内存不足在疯狂换页;util%长期接近100%,说明存储盘的性能已经到极限。这些证据比任何AWR里的“耗时”都更接近物理真相。

再比如alert日志里出现ORA-00600 [17182],很多DBA第一反应是Bug,但我在OS的/var/log/messages里看到的是OOM killer直接干掉了数据库进程。OS没内存了,把oracle进程杀了,数据库内部再排查也不解决根本问题。这就是“数据库日志正常,操作系统日志要命”的典型例子。

5.2 别让网络背锅,但更不能忽略网络丢包

数据库会话等待SQL*Net message from client时,很多新手会把这条当成问题,其实这是个“伪等待”。它只是会话在等客户端发送下一条指令,数据库这边什么事都没干。真正的风险在于:如果客户端在跨机房的链路上经常丢包、重传,一次普通的SQL请求在网络上反复重传,用户感知到的就是“数据库卡了”。

这种情况下数据库侧的所有日志都不会有异常,你必须到操作系统的网络层找证据:

# 查看网卡丢包、错误统计(注意看drop与errors列) netstat -i # 或者在客户端与服务端之间抓包统计TCP重传 tcpdump -i eth0 tcp port 1521 -w /tmp/client.pcap

抓到包之后用wireshark打开,重点看TCP Delta和重传标记。如果一段正常的SQL查询往返时间在数据库内只有5毫秒,而TCP层却耗时200毫秒,那结论很清晰:链路质量背锅,别再把开发叫过来改SQL了。

5.3 存储日志:数据库看到的是表象,存储报的是实底

数据库等待db file sequential read平均要几十毫秒,几乎可以断定不是数据库自身问题。这时候建议登录存储管理端,看物理磁盘的健康状态和延迟指标。

我遇到过一个“诡异卡顿”:数据库AWR显示I/O等待很高,但OS的iostat延迟正常。后来存储工程师在阵列日志里发现某块磁盘的扇区重读次数暴涨,触发了磁盘降级,阵列内部在做重建,数据访问全部被拖慢。这种事在数据库日志里看不到,在OS层面也可能被阵列缓存掩盖,只有存储日志才能扫出来。

所以跨界排查的次序,我建议是:先数据库内、再数据库外,但最终一定要走到OS和存储日志。很多折腾一夜的卡顿,最后发现就是底层硬件或网络链路的问题。

6. 我自己常用的卡顿排查顺序与几个实操建议

6.1 一张可以直接抄走的检查清单

排查卡顿类问题,我给自己定了一个固定套路,现在分享出来:

步骤检查内容关键命令/视图判断目标
1. 确认范围报警描述、影响模块、持续时间问业务人员判定全库型还是单会话型
2. 看alert日志最近错误、死锁、日志切换问题adrci show alert -tail排除内部错误、归档、OOM
3. 抓当下状态当前活动的会话与等待事件v$session、v$sqlarea锁定等待事件与阻塞链
4. 回溯时间轴卡顿时刻ASH/DBA_HIST_ACTIVE_SESS_HISTORYv$active_session_history定位具体SQL与对象
5. 对照AWR/ADDM数据库自身负载画像awrrpt.sql、addmrpt.sql看TOP事件、TOP SQL、Top Objects
6. 查OS日志与指标CPU/I/O/内存/网络sar、iostat、netstat、/var/log/messages排除数据库外因素
7. 结合存储日志磁盘健康、延迟、控制器存储在对应管理界面排除底层故障

这套顺序的核心逻辑,是从“数据库告诉我的”逐步外推到“数据库告诉我的内幕”。一定不要把时间花在逐条翻日志上,要先把时间轴建立起来。

6.2 平时把“弹药”备足,卡顿时才不吃力

说句实在话,排查卡顿最怕的不是没日志,而是需要历史数据的时候发现没采集过。有几个基础习惯我建议你提前养成:

  • 确认AWR和ASH采集是开启状态,statistics_level至少是TYPICAL,AWR自动快照间隔建议30分钟或更短;
  • 给alert日志和监听日志所在的文件系统设置独立的告警阈值,磁盘满之前就会提前收到风声;
  • 遇到重大卡顿,第一时间手动保存一个AWR快照对和ASH dump,这才是卡顿发生后最珍贵的现场数据;
  • 至少每月做一次redo切换频率和归档空间趋势检查,很多周期性的“卡一下”都能从趋势里提早发现。

6.3 最后一个经验:把“卡顿”当刑事案件办,别急着下结论

排查无数次卡顿之后,我的体会是:最贵的教训来自“先入为主”。一看等待事件是I/O就认定存储慢,结果存储那边查了三天,最后发现是某张表被全表扫描了千万行;一看SQL耗时就改SQL,结果发现是网络重传让一条毫秒级SQL来回跑了几十趟。

正确的动作是:先取证,再定案。把业务感知、数据库内部证据、OS证据、网络与存储证据全部摆到一张时间轴上,找到那个唯一能解释所有现象的点。日志是“案发现场”,等待事件是“目击证人”,操作系统日志和存储日志是“法医报告”,每个角色都不能少。

最后说句掏心窝子的话:排查Oracle卡顿相关日志这件事,最终拼的不是你对某一条命令多熟,而是你有没有一套能反复验证的时间线思维。先确认“卡”在哪一层,再去翻对应的日志,你的排查效率至少能提高一倍。希望这份清单能让你少走几次我走过的弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 5:04:14

JY901校准算法实战:从零偏标定到磁力计椭球拟合的完整指南

简介:这份资源围绕JY901模块的校准算法展开,面向使用MPU9050传感器进行姿态解算的嵌入式开发者与飞控爱好者,重点解决磁场与加速度输出存在零偏、导致航向角与倾角精度下降的问题。包内为1个docx文档,压缩包约16KB,以文…

作者头像 李华
网站建设 2026/10/15 5:03:01

HTML面试题必备清单,再也不怕丢失!

每次面试都得看一遍面试题,每次准备的都放在了 Word 上,但是都误删丢失了,所以记录在这个地方吧。html面试题问题:什么是语义化标签?为什么要使用语义化标签?答案:语义化标签是指使用具有明确含义的 HTML 标签来描述页面内容,如 <header>、<nav>、<main…

作者头像 李华
网站建设 2026/10/15 5:02:38

Hive collect_list有序性陷阱与三种可靠排序方案

1. 从一次数据对账事故说起&#xff1a;collect_list为什么不是"收集完再排序"那么简单去年帮一个做用户行为分析的团队排查数据问题时&#xff0c;遇到一个很典型的场景。他们需要把每个用户过去30天的行为事件按时间顺序拼成一条链路&#xff0c;用来做路径分析和漏…

作者头像 李华
网站建设 2026/10/15 5:02:32

路由器分组交换与存储转发:从延迟根源到网络设计哲学

1. 从一个让人抓狂的延迟说起你有没有遇到过这种情况&#xff1a;晚上在家打游戏&#xff0c;正到团战关键时刻&#xff0c;画面突然卡住&#xff0c;人物瞬移&#xff0c;等反应过来已经躺地上了。你骂运营商、骂路由器、骂网线&#xff0c;但很少有人会去想一个更底层的问题—…

作者头像 李华
网站建设 2026/10/15 5:02:02

Spark BulkLoad 写入 HBase 多列场景实战:HFile 生成与避坑指南

1. 项目背景与核心需求拆解1.1 为什么会有这个需求手里有一批数据要进HBase&#xff0c;量还不小&#xff0c;每天增量在千万级别。最开始用的是HBase原生的Put API&#xff0c;单条或者批量提交&#xff0c;跑了一段时间发现两个问题&#xff1a;一是写入吞吐上不去&#xff0…

作者头像 李华
网站建设 2026/10/15 5:02:02

多Agent系统选型实录:为何Hermes成为综合Agent核心

如果你正在搭一个多 Agent 系统&#xff0c;或者正在纠结要不要把某个中间件提成团队的“综合 Agent 核心”&#xff0c;那我这篇内容应该能帮到你。HagiCode 是我们这边内部跑了大半年的一个多 Agent 协同项目&#xff0c;早期一直用的是一套自研的工具调用调度模块&#xff0…

作者头像 李华