1. 卡顿排查,先从日志体系的整体认知开始
做Oracle运维的人都知道,数据库一卡顿,业务方电话打过来,第一句话基本都是“库是不是又慢了,赶紧看看”。这时候如果漫无目的地开几个查询去瞎猜,大概率会浪费宝贵的故障时间。真正有经验的做法是:先把数据库的日志体系在心里过一遍,知道每一种日志记录了什么、在哪里、怎么快速调取,然后才是具体的分析动作。
Oracle的日志和诊断文件分布在多个层面,大致可以分成这几类:告警日志(Alert Log)、跟踪文件(Trace File)、监听日志(Listener Log)、性能统计快照(AWR/ASH/STATSPACK)、以及操作系统层面的日志。告警日志记录数据库的重大事件、错误和启动关闭过程,这是排查卡顿的第一入口;跟踪文件则记录某个会话或后台进程的详细活动,适合深挖单条SQL或单独进程的问题;监听日志负责记录客户端连接请求,连接慢或连接风暴的时候就看它;AWR和ASH是性能历史档案,卡顿结束之后用来复盘、对比、定位性能瓶颈最合适。
这里有一个非常重要的认知:卡顿不是随机发生的,它一定有迹可循。不管是SQL性能恶化、锁等待、I/O瓶颈,还是日志切换缓慢、内存竞争,都会在相应日志或性能视图里留下线索。排查的本质,就是把分散在不同位置的证据串成一条完整的时间线。所以我在处理这类问题时,脑子里一直装着一句话:先看时间线,再找异常,最后做根因分析。带着这个思路去看日志,效率会高非常多。
| 日志类型 | 默认位置(常见环境) | 核心作用 | 卡顿排查价值 |
|---|---|---|---|
| 告警日志 alert_{SID}.log | $ORACLE_BASE/diag/rdbms/{dbname}/{SID}/trace/ | 记录错误、启动关闭、参数变更、日志切换 | 定位故障发生时间和错误号 |
| 跟踪文件 .trc | 上述同目录或用户指定目录 | 记录会话级详细活动、SQL执行计划、等待事件 | 深挖具体会话卡在哪一步 |
| 监听日志 listener.log | $ORACLE_BASE/diag/tnslsnr/{hostname}/listener/ | 记录连接请求、注册信息 | 排查连接慢、连接数打满的问题 |
| AWR 报告 | 数据字典中历史快照 | 保存性能基线数据 | 卡顿前后的指标对比分析 |
| ASH 活动会话历史 | 内存及数据字典历史表 | 记录活动会话的采样快照 | 精准定位卡顿时刻的活动SQL |
| 归档日志 | 由参数指定目录 | 保存重做日志的历史文件 | 排查归档空间满、日志断档问题 |
这一套日志体系,我建议每位DBA都画一张自己环境里的目录树存好。真到故障发生的时候,少走一步弯路都是赚的。
2. 告警日志:定位卡顿的第一战场
2.1 告警日志里到底能看到什么
告警日志是Oracle数据库的“黑匣子”,它按时间顺序记录数据库生命周期里所有关键事件。举几个实际工作中最常见的例子:
ORA-00600内部错误、ORA-07445进程异常崩溃,这类错误出现的时候,通常伴随严重的性能问题或进程异常;日志切换卡顿和检查点未完成,会直接导致数据库瞬间卡死;ORA-00060死锁检测到的提示,意味着有会话互相持有对方需要的资源,形成死循环等待;表空间扩展失败、ORA-01653这类错误,会造成业务写入直接报错。还有一些参数变更记录、redo日志大小调整、回滚段扩展等操作记录,也会在其中留下踪迹。
很多人对告警日志有个误区,认为它只记录错误。实际上它还会记录很多“看起来正常但实际有问题”的信息。典型的例子是日志切换频繁。有时候告警日志里看不到任何ORA-错误,全是正常的日志切换信息,但如果切换频率高到每几分钟就切一次,重做日志写入的I/O开销会拖慢整个库的性能。这种问题光看错误日志是发现不了的,必须结合切换频率来综合判断。
查看告警日志最直接的办法是直接找到文件用tail查看最新内容:
# 进入告警日志目录 cd $ORACLE_BASE/diag/rdbms/orcl/orcl/trace # 查看最新100行 tail -100 alert_orcl.log # 带时间关键字筛选 grep "ORA-" alert_orcl.log | tail -50在较新版本的Oracle中,推荐使用ADRCI命令行工具来查看,好处是不用手动找目录、支持按时间过滤:
adrci> show alert -tail 50 adrci> show alert -last 36002.2 用“时间线串联法”定位卡顿起点
处理过几次生产库卡顿之后,我总结了一个特别实用的排查方法,自己叫它“时间线串联法”。思路非常简单:拿到业务反馈的卡顿时间段之后,先去告警日志里把这个时间点前后半小时的所有异常、警告、错误全部捞出来排个序,然后再去配合操作系统日志和性能视图验证。
具体操作流程大概是这样的。第一步,确定故障发生的精确时间,这个要问业务,最好能精确到分钟级;第二步,执行如下命令,把故障时间前后一定范围内的告警日志内容整体导出:
# 假设故障窗口是 2025-01-10 14:00 ~ 14:30 awk '/2025-01-10 1[34]/' alert_orcl.log > /tmp/card_log.txt grep -E "ORA-|Errors|Warning|abort|terminated" /tmp/card_log.txt第三步,把筛出来的内容按时间排序,找到最早出现的异常信息,这个大概率就是问题的起点。举个例子,某次我排查一个卡顿问题,业务反馈14点开始系统变慢。我在告警日志里看到14:01有一条ORA-00060死锁记录,14:03又出现一条,然后每隔几分钟就出现一次。顺着这个线索查下去,发现是一个批量更新任务和前台业务程序之间出现循环等待,最终锁住了热点表。如果只看业务反馈的时间,不去告警日志里抓第一个异常点,这问题查起来要绕不少弯路。
2.3 实操心得:别只盯着ORA-错误看
这是我想特别强调的一点。告警日志里经常出现ORA-错误,但并不代表所有ORA-错误都值得你处理,有些只是“症状”而不是“病根”。举一个真实遇到的例子:某次数据库卡顿,告警日志里刷了一堆ORA-01653(表空间无法扩展),看着像磁盘空间不足。但实际查下去才发现,真正的原因是某个失控的SQL查询全表扫描,把临时表空间撑爆了,导致后续写入全部失败。如果盯着表空间扩容去做,问题根本解决不了,过两天还会再次爆发。
我个人的习惯是,在告警日志里看到任何ORA-错误,都先问三个问题:这个错误是什么时候开始出现的?它的频率是持续上升还是保持稳定?它和业务反馈的卡顿时间段是否吻合?只有把这三个问题放进时间线里做交叉验证,才能判断它到底是因还是果。
另外一个容易忽略的点是检查点相关提示。当数据库出现“Checkpoint not complete”这类信息时,意味着日志切换时检查点还没跟上,数据库会强制等待,这个瞬间的卡顿往往在几百毫秒到几秒之间,用户感知非常明显。这类问题在日志里没有红色错误提示,只有一行看似普通的警告,很多DBA会直接跳过。所以看告警日志,尤其是排查卡顿类问题时,要养成把“警告级”信息也翻一遍的习惯。
3. 跟踪文件与会话级日志:拿到第一手现场证据
3.1 跟踪文件的价值与分类
告警日志能告诉我们“发生了什么”,但想知道“具体哪个会话在做什么、为什么慢”,就得靠跟踪文件了。跟踪文件在Oracle里分为两类:后台进程跟踪文件和用户会话跟踪文件。后台进程跟踪文件记录了DBWR、LGWR、CKPT这些核心后台进程的活动,当数据库整体响应变慢时,查看这些进程的跟踪文件可以判断是不是某个关键后台进程卡住了。用户会话跟踪文件则记录了具体业务会话的SQL执行细节,包括等待事件、解析时间、执行计划等。
我一般排查卡顿的逻辑是:先用告警日志确定问题的大致方向,再用跟踪文件对可疑会话做定点深挖。比如数据库整体不算堵,但某一类业务的查询特别慢,这种时候定位到具体会话、开启会话跟踪是最直接的。
3.2 如何抓取一个正在卡顿的会话的跟踪信息
生产环境中我们经常遇到这样的场景:业务说某条SQL昨天还很正常,今天突然跑不动了。想查原因,但SQL执行完就结束了,想重跑一遍又怕影响生产。这时候最好的办法是:在SQL运行期间直接抓会话的实时等待信息。
先找到正在运行的会话信息:
-- 查看当前有哪些会话正在执行SQL,以及它们的等待事件 SELECT s.sid, s.serial#, s.username, s.event, s.wait_time, s.sql_id, s.status, s.blocking_session FROM v$session s WHERE s.type = 'USER' AND s.status = 'ACTIVE' ORDER BY s.event;这里需要多说两句v$session里几个关键列的含义。event列显示的是当前正在等待的事件,如果是“SQL*Net message from client”表示在等客户端发送数据,问题在网络或应用层;如果是“db file sequential read”表示在做单块读等待,通常是索引扫描的I/O瓶颈;如果是“enq: TX - row lock contention”则表示在等待行锁释放。blocking_session列如果非空,说明这个会话被另一个会话阻塞了,顺着这个字段可以一路追到会话源头。
定位到急于抓取SQL的会话之后,可以用DBMS_MONITOR包对指定会话开启跟踪:
-- 对指定SID开启SQL跟踪 BEGIN DBMS_MONITOR.SESSION_TRACE_ENABLE( session_id => 123, serial_num => 456, waits => TRUE, binds => TRUE ); END; /执行完这条语句后,该会话后续执行的SQL、等待事件、绑定变量都会被记录到用户跟踪文件里。等到SQL跑完、业务反馈恢复正常,再关闭跟踪:
BEGIN DBMS_MONITOR.SESSION_TRACE_DISABLE(session_id => 123, serial_num => 456); END; /然后去USER_DUMP_DEST目录找对应的.trc文件,用tkprof工具格式化输出:
tkprof /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_12345.trc /tmp/trace_report.txt sort=prsela,exela,fchela这里要重点说说tkprof排序参数。sort=prsela表示按SQL解析耗时排序,sort=exela表示按执行耗时排序,sort=fchela表示按数据获取耗时排序。排查卡顿时我最常用的是exela,能把最耗时的SQL排在前面。格式化后的报告里会明确列出每个SQL的解析时间、执行时间、获取行数、CPU时间,以及占用的比例。
3.3 用10046事件做深度诊断
有些极端情况,数据库不是“慢”,而是“卡死”了一样,会话在某个事件上等待几十秒甚至几分钟。这种时候常规的v$session查询可能都不太够用,需要更细粒度的诊断信息,建议用10046事件来做内部诊断。10046事件本质上是Oracle内部跟踪机制,按不同level记录不同粒度的信息:level 1记录SQL语句文本和解析执行统计;level 4在1的基础上增加绑定变量信息;level 8记录等待事件;level 12则是4和8的组合,能拿到最完整的诊断信息,这也是我最常用的配置。
对当前会话开启10046事件:
ALTER SESSION SET events '10046 trace name context forever, level 12';然后执行那条有问题的SQL,执行完关闭跟踪:
ALTER SESSION SET events '10046 trace name context off';生成的跟踪文件里会包含每条SQL执行时每一个等待事件的开始时间、持续时长、等待类型。我经常用这个方法来定位某些时快时慢的SQL,找出它们在执行计划中具体卡在了哪一步。比如有一次,一条关联查询平时跑0.5秒,某段时间突然变成10秒,用10046看完之后发现不是SQL本身的问题,而是它在等某张表的统计数据收集完成,后续SQL全部排队。这种情况如果没有10046级别的等待细节,很难想象到问题会出在统计信息收集任务上。
3.4 实操记录:一个完整的会话抓取流程
某次模拟项目X的压测环境中,业务反映订单查询接口响应时间从正常的200毫秒飙到3秒以上。我按下面的顺序做了排查:
第一步,用上面的v$session查询找出活跃会话,发现大量会话的event都是“buffer busy wait”,而且集中在某张订单明细表的数据块上;第二步,通过blocking_session字段顺藤摸瓜,找到一个正在做全表更新的大事务会话,它就是元凶;第三步,对这个大事务会话开启10046跟踪,确认它更新涉及的行数远超正常业务量;第四步,结合告警日志,发现这个时间段刚好有批量导入任务启动,和前台订单写入撞到了一起。
整个过程用时大概二十分钟。如果没有跟踪文件给出的等待事件细节,仅凭告警日志里的错误信息很难定位到这个层面的问题。
4. 性能日志的高级玩法:ASH与AWR的实战配合
4.1 ASH:卡顿发生当时的“行车记录仪”
如果说告警日志是黑匣子,那ASH就是行车记录仪。它每秒从活跃会话里采样一次,记录每个会话当时在执行的SQL、等待的事件、消耗的资源。Oracle把这份数据存在内存里,并定期刷到历史表dba_hist_active_sess_history中。这个特性对排查卡顿有一种别的手段无法替代的价值:即使当时没有开任何跟踪,事后也能还原出那个时间点到底发生了什么。
当业务反馈“刚才卡了十分钟,现在恢复了”的时候,我们完全可以事后去查看那十分钟里所有会话的活动。举例来说:
-- 查询某时间段内卡顿的活动会话分布 SELECT TO_CHAR(sample_time, 'HH24:MI:SS') sample_min, session_state, event, COUNT(*) cnt FROM dba_hist_active_sess_history WHERE sample_time BETWEEN TO_DATE('2025-01-10 14:00:00', 'YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2025-01-10 14:30:00', 'YYYY-MM-DD HH24:MI:SS') AND dbid = (SELECT dbid FROM v$database) GROUP BY TO_CHAR(sample_time, 'HH24:MI:SS'), session_state, event ORDER BY sample_min, cnt DESC;这个查询跑出来的结果,能直接展示时间维度上的性能变化曲线。比如14:00到14:05之间,几乎所有会话都在等待“enq: TX - row lock contention”,那就是锁问题;14:05之后等待消失,会话恢复运行,说明锁已经释放。把采样时间和等待事件一对照,问题的轮廓就出来了。
再往下追一步,定位具体卡顿的SQL:
-- 找到卡顿时间段内最消耗资源的SQL SELECT sql_id, COUNT(*) cnt, ROUND(COUNT(*) * 100 / SUM(COUNT(*)) OVER (), 2) pct FROM dba_hist_active_sess_history WHERE sample_time BETWEEN TO_DATE('2025-01-10 14:00:00', 'YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2025-01-10 14:30:00', 'YYYY-MM-DD HH24:MI:SS') GROUP BY sql_id ORDER BY cnt DESC FETCH FIRST 10 ROWS ONLY;这个结果能告诉我们:卡顿期间哪几条SQL占据的会话时间最长。我遇到过不少案例,卡顿的根本原因不是SQL本身慢,而是某条SQL占用了大量资源,把别的SQL挤到一边去等待。ASH的会话采样分布在识别这种“资源抢占型”问题时特别有用。
4.2 AWR报告:用对比找出性能偏差
AWR报告是Oracle自动生成的性能报告,默认每小时拍一张快照,保存最近7天(可配置)的统计数据。它的价值不在单张报告本身,而在对比。同一套系统,和正常时段的性能指标做对比,往往能发现卡顿时段的异常指标。
生成AWR报告的方式很简单,登录SQL*Plus执行:
@?/rdbms/admin/awrrpt.sql按照提示依次选择报告类型(HTML或文本)、选择起始快照ID、结束快照ID,就会生成一份报告。我建议做两个对比:一是卡顿时间段的前后快照对比,二是卡顿时间段和一周前同一天的正常时段对比。
拿到报告后我一般快速扫几个关键指标:Top 5 Timed Events区域,如果某个等待事件的占比特别高比如超过50%,基本就能锁定瓶颈方向;SQL Statistics区域里的SQL ordered by Elapsed Time,看哪些SQL消耗时间最多;Segment Statistics区域观察哪些段被访问异常频繁;I/O Stats区域检查物理读、写是否过大。
举一个实际案例。某系统的AWR报告显示Top 1等待事件是“log file sync”占比超过70%。所谓log file sync,本质上是用户会话提交事务时等待日志写入完成。看到这个指标,结合之前从告警日志里看到的频繁日志切换记录,我判断问题的核心是磁盘I/O能力跟不上重做日志写入量。后来验证发现,重做日志所在的磁盘组同时承载了大量其他业务的写入,造成I/O竞争。后面把日志文件单独迁移到独立的存储卷,问题直接解决。再看一眼卡顿时间段和正常时间段的I/O对比,物理读取量翻了差不多五倍,这个数据的指向性已经非常明显了。
4.3 从ASH到AWR:两层数据互为印证
不少新手DBA容易犯一个错误:只会用AWR,或者只会用ASH,两者完全是割裂的。我在实际工作中已经形成一套固定打法:先用ASH定位具体时间点的活动会话分布,确定问题和哪些SQL、哪些等待事件相关;再用AWR报告验证这些等待事件在更长时间跨度上的占比趋势,确认问题是偶发还是持续存在。
实操中的判断逻辑很简单:如果ASH里看到的问题SQL和等待事件在AWR报告的Top事件里占比也很高,那说明问题不是抽样偶然,而是系统性的性能瓶颈;如果ASH里问题很突出但AWR报告整体看起来基本正常,那说明问题更偏向短时突发,可能是某种临时性锁冲突或并发峰值导致。
5. 等待事件:连接日志与根因的桥梁
5.1 等待事件的基本逻辑
Oracle里几乎所有性能问题最终都会表现为某个等待事件。这句话我在各种场合反复念叨,因为它确实太重要了。会话在运行SQL时,如果不需要等待任何资源,那SQL的耗时就是纯CPU时间;一旦出现资源争用,比如磁盘慢了、锁冲突了、内存不够了,会话就会进入等待状态,等待事件就记录了它“在等什么”以及“等了多久”。
排查卡顿的核心就是把等待事件和业务时间段、日志信息做交叉分析。等待事件分类繁多,但对于排查卡顿来说,掌握几类最常见的其实就够用了。I/O类等待事件提示磁盘读写慢,比如db file sequential read是单块读等待,db file scattered read是多块读等待,direct path read是在做直接路径读;锁等待类提示并发冲突,比如enq: TX - row lock contention是行锁等待,enq: TM - contention是表锁等待;日志提交类反映重做日志写入压力,log file sync是提交等待日志落盘;此外还有CPU调度类的“CPU used by this session”,表示会话本身在消耗CPU,而不是在等什么东西。
5.2 用等待事件快速判断卡顿性质
根据等待事件的分布情况,可以把卡顿问题粗分成几种性质,然后针对性地去查对应的日志和配置。
如果大量会话都集中在I/O类等待上,这就是明显的I/O瓶颈型卡顿。这时候要看操作系统的I/O监控工具,配合AWR里Tablespace I/O统计和Datafile I/O统计,确认是不是特定表空间或数据文件所在的磁盘拖了后腿。再结合告警日志里有没有“log file switch completion”这类日志切换等待,可以进一步判断是数据文件慢还是重做日志慢。
如果大量会话等待在锁事件上,则是并发锁冲突型卡顿。这时候重点查v$lock,看是谁持有锁、谁在等锁,配合DBA_BLOCKERS和DBA_WAITERS视图定位阻塞链。告警日志如果出现ORA-00060,那就是死锁现场的直接证据。
如果等待事件以log file sync和log file parallel write为主,则是日志写入瓶颈型卡顿。要看日志文件所在磁盘的I/O能力,可能需要调大日志文件、增加日志组成员,或者把日志迁移到更快的存储上。
如果卡顿时段明明跑着一个CPU密集的SQL,但等待事件里没有明显等待,而是大量CPU used,这时要回到SQL执行计划里去分析,看看是不是表连接顺序有问题、使用了低效的嵌套循环、或者没有走索引导致大范围扫描。
5.3 等待事件排查案例
某次一个业务系统在每天晚上8点左右准时变慢,业务方多次反馈但一直没找到原因。我查了告警日志,前后几天在这个时间段都没有任何错误信息。改用ASH查询之后发现,卡顿时段会话的等待事件高度集中在“enq: TX - index contention”上,当时就觉得很奇怪,因为索引竞争通常意味着大量的并发插入,而且都往索引的同一个块上写入,这个特征在顺序主键的场景下很典型。顺着这个线索去查每日8点的定时任务,发现确实有个批量数据导入的作业在集中插入新一批业务数据,而表上的主键索引又恰好是顺序递增的,所有会话都去抢索引的同一个叶子块,竞争自然就非常激烈。后续把数据导入的时间调整到业务低峰期,问题直接消失。如果把这类问题当成普通SQL慢来处理,很可能原地打转很久,因为SQL本身一点都不慢,慢的是它引发的竞争。
5.4 一个实用的等待事件速查思路
我自己习惯的做法是,在排查卡顿时不直接上来就看等待事件的完整列表,而是先按时间维度统计等待事件的分布比例,让“哪类事件在哪个时间段集中出现”一目了然。下面的查询就是干这个用的:
SELECT TO_CHAR(sample_time, 'HH24') hour_bucket, event, COUNT(*) cnt FROM dba_hist_active_sess_history WHERE sample_time >= SYSDATE - 1 GROUP BY TO_CHAR(sample_time, 'HH24'), event ORDER BY hour_bucket, cnt DESC;这样查完之后,我会把数值最突出的几个事件单独拉出来,再结合对应的SQL_id做定点分析。整个流程下来,问题基本就能锁定到很小的范围内,剩下的就是针对性地看执行计划或调整参数了。
6. 常见问题与排查技巧实录
6.1 排查中常见的陷阱
做了这么多年Oracle运维,我踩过的坑不少,这里挑几个最有代表性的分享出来。
第一个坑:只查数据库日志,不看操作系统层面配合。磁盘空间满了、内存不足、网络抖动,这些问题很多时候先在操作系统日志里出现,然后才引发数据库异常。我处理过的案例里,有两次数据库卡顿,最终问题都出在存储交换机故障导致磁盘I/O大面积波动。这种问题光看数据库内部日志容易让人摸不着头脑,告警日志里只有I/O错误,操作系统日志才真正揭示了存储层的异常。数据库层面和操作系统层面的日志必须一起看,交叉验证。
第二个坑:卡顿已经恢复了才接到反馈,没有现场可查。这种时候最忌讳的是直接放弃,觉得问题没法查了。ASH历史数据和AWR报告就是为这种场景准备的,至少能把可疑SQL和等待事件拉出来复盘。此外,如果平时有定期采集AWR并保留历史报告的习惯,那排查起来就更从容了。
第三个坑:错误地依赖单一指标下结论。比如某次看到等待事件以db file sequential read为主,直接认定是磁盘I/O慢。结果后来发现磁盘指标完全正常,真正的问题是执行计划因为统计信息过期走了错误的索引。等待事件是现象,不是根因,判断一定要配合执行计划、统计信息、SQL文本综合来看。
6.2 常见卡顿问题速查表
| 卡顿表现 | 典型等待事件 | 首先排查位置 | 高频根因 |
|---|---|---|---|
| 整体响应慢,磁盘繁忙 | db file sequential read / scattered read | AWR I/O统计、OS磁盘监控 | 磁盘I/O能力不足、SQL低效扫描 |
| 特定会话卡住不动 | enq: TX - row lock contention | v$session.blocking_session | 未提交事务持有行锁 |
| 频繁提交时报慢 | log file sync | 重做日志所在磁盘 | 日志写入I/O慢、磁盘竞争 |
| 所有会话短时挂起 | log file switch completion | 告警日志检查点记录 | redo日志太小、切换频繁 |
| 大批量插入时变慢 | enq: TX - index contention | 索引顺序和分布 | 索引叶子块热点竞争 |
| 应用偶发超时 | SQL*Net message from client | 监听日志 | 应用服务端异常、网络延迟 |
| 跑批任务集中时报错 | ORA-01653 | 表空间使用率 | 表空间不足、段自动扩展失效 |
6.3 几条很有价值的排查心得
关于日志的保存和归档,我现在的做法是给每套库配置日志轮转策略,告警日志、监听日志都做定期归档清理,同时把定期生成的AWR报告统一归档保存。这样万一哪天真出了问题,历史数据随手就能找到,可以对比“正常时”和“出问题时”的差异。没有历史基线,很多性能问题根本就没法判断“异常”的边界在哪里。
关于日常巡检,我强烈建议DBA每周至少看一眼告警日志里最近的ORA-错误,哪怕系统运行看起来很稳定。很多卡顿问题的隐患其实早期就会有零星记录,比如偶尔的锁超时、偶发的日志切换慢,如果当时就深挖一下,往往能防患于未然。我自己就有过一次教训:某系统出现过几次零星的ORA-00060,当时觉得偶发无所谓,结果一个月后变成了严重的死锁风暴。从那以后,再也不敢忽视任何一条偶发错误了。
关于处理优先级,我个人的经验是:遇到数据库卡顿,第一时间先确认有没有锁和阻塞,第二时间确认redo日志切换和归档是否正常,第三时间才去看SQL性能。这个顺序的依据是:锁问题和日志切换问题可能导致的现象最严重,有时候会波及全库,影响面最大;而SQL性能问题通常只影响单个或少数会话,影响相对可控。先把能造成“大面积卡顿”的因素排除掉,再处理局部问题,排查效率会高很多。
另外补一个小技巧:如果发现某个时间段的ASH数据里,活动会话数突然飙高,随后断崖式下降,这往往暗示数据库在这个时间点经历过一次大范围的阻塞集中释放。这时对比一下阻塞释放前后执行完成的SQL,通常能找到那个“被憋了很久然后突然放行”的大事务,它就是引发这波卡顿的核心对象。
排查Oracle卡顿这件事,经验和工具同等重要。工具就摆在那里,日志也都在那里,差别就在于你是否能在最短时间内定位到对的那一份,并在其中找到最关键的证据。