三、查看阻塞lock
排查结果:无
SELECT mm.inst_id, mm.sid, mm.TYPE, mm.id1, mm.id2, LPAD(TRUNC(mm.ctime / 60 / 60), 3) || ' Hour ' || LPAD(TO_CHAR(TRUNC(mm.ctime / 60) - TRUNC(mm.ctime / 60 / 60) * 60, 'fm09'), 2) || ' Min ' || LPAD(TO_CHAR(mm.ctime - TRUNC(mm.ctime / 60) * 60, 'fm09'), 2) || ' Sec' ctime, CASE WHEN mm.block = 1 AND mm.lmode != 0 THEN 'holder' WHEN mm.block = 0 AND mm.request != 0 THEN 'waiter' ELSE NULL END role, CASE WHEN ee.blocking_session IS NOT NULL THEN 'waiting for SID ' || ee.blocking_session ELSE NULL END blocking_session, dd.sql_text sql_text, cc.event wait_event FROM gv$lock mm, gv$session ee, gv$sqlarea dd, gv$session_wait cc WHERE mm.sid IN (SELECT nn.sid FROM (SELECT tt.*, COUNT(1) OVER (PARTITION BY tt.TYPE, tt.id1, tt.id2) cnt, MAX(tt.lmode) OVER (PARTITION BY tt.TYPE, tt.id1, tt.id2) lmod_flag, MAX(tt.request) OVER (PARTITION BY tt.TYPE, tt.id1, tt.id2) request_flag FROM gv$lock tt) nn WHERE nn.cnt >1 AND nn.lmod_flag != 0 AND nn.request_flag != 0) AND mm.sid = ee.sid (+) AND ee.sql_id = dd.sql_id (+) AND mm.sid = cc.sid (+) AND ((mm.block = 1 AND mm.lmode != 0) OR (mm.block = 0 AND mm.request != 0)) ORDER BY mm.TYPE, mm.id1, mm.id2, mm.lmode DESC, mm.ctime DESC四、查看是否有正在运行的定时任务
排查结果:无
--查询正在执行的scheduler_jobselect owner,job_name,sid,b.SERIAL#,b.username,spid from ALL_SCHEDULER_RUNNING_JOBS,v$session b,v$process where session_id=sid and paddr=addr五、从AWR报告做分析
前面四条SQL只是凭经验去快速定位,看来快速定位找不到问题,只能拿故障时间段的awr进行整体分析了,如果时间点能更细那就再拿ASH看。
1、awr概览
Instance Efficiency Percentages (Target 100%)所有指标 的目标均为100%,即越大越好,在少数bug情况下可能超过100%或者为负值。
标准是:
- 80%以上 %Non-Parse CPU
- 90%以上 Buffer Hit%, In-memory Sort%, Soft Parse%
- 95%以上 Library Hit%, Redo Nowait%, Buffer Nowait%
- 98%以上 Latch Hit%
可以看到Buffer Hit %: 是不达标的
Memory Usage %:对于一个已经运行一段时间的数据库来说,共享池内存使用率,应该稳定在75%-90%间,
SQL with executions>1:执行次数大于1的sql比率,如果此值太小,说明需要在应用中更多使用绑定变量,避免过多SQL解析。
Memory for SQL w/exec>1:执行次数大于1的SQL消耗内存的占比。这是与不频繁使用的SQL语句相比,频繁使用的SQL语句消耗内存多少的一个度量。
2、时间模型分析
在awr中,Time Model Statistics用于回答“到底前台进程消耗了多少时间?”,“语句解析消耗了多少时间?”等诸如此类的问题。
这里可以看到排在最前的是SQL execute elapsed time ,该值代表SQL statements 运行所花费的总的时间 , 注意对于 select 语句来说 . 这相同包含获取 (fetch) 查询结果的时间。
可以看到用于sql执行的时间(sql execute elapsed time)占到了95.02%,作来一个相对正常的系统,这一比率不应低于90%甚至更高。
ps:
parse time elapsed、hard parse elapsed time 结合起来看解析是否是主要矛盾,若是则重点是软解析还是硬解析
sequence load elapsed time sequence序列争用是否是问题焦点
PL/SQL compilation elapsed time PL/SQL对象编译的耗时
注意PL/SQL execution elapsed time 纯耗费在PL/SQL解释器上的时间。不包括花在执行和解析其包含SQL上的时间
connection management call elapsed time 建立数据库session连接和断开的耗时
failed parse elapsed time 解析失败,例如由于ORA-4031
hard parse (sharing criteria) elapsed time 由于无法共享游标造成的硬解析
hard parse (bind mismatch) elapsed time 由于bind type or bind size 不一致造成的硬解析
3、等待事件分析
从等待事件可以看出主要是I/0上的瓶颈,其中commit平均等待16ms,后台log file paralle write平均8ms确实太慢了,初步判断系统明显卡顿。
ps:常见的等待事件和解决方法
4、TOP SQL分析
从以上结果分析,主要问题是在I/0上,如果是从整体优化还是需要从SQL ordered by User I/O Wait Time(I/0等待时间)、SQL ordered by Gets(逻辑读)、SQL ordered by Reads(物理读)四个方面去找sql做优化。
但以下涉及的sql均属于日常用到的,没明显异常,但系统却突然卡顿?
说明:
- CPU TIME : 该SQL 在快照时间内累计执行所消耗的CPU 时间片,单位为s
- Executions : 该SQL在快照时间内累计执行的次数
- CPU per Exec (s) :该SQL 平均单次执行所消耗的CPU时间 , 即 ( SQL CPU TIME / SQL Executions )
- %Total : 该SQL 累计消耗的CPU时间 占 该时段总的 DB CPU的比例, 即 ( SQL CPU TIME / Total DB CPU)
- % CPU 该SQL 所消耗的CPU 时间 占 该SQL消耗的时间里的比例, 即 (SQL CPU Time / SQL Elapsed Time) ,该指标说明了该语句是否是CPU敏感的
- %IO 该SQL 所消耗的I/O 时间 占 该SQL消耗的时间里的比例, 即(SQL I/O Time/SQL Elapsed Time) ,该指标说明了该语句是否是I/O敏感的。
说明:
- Buffer Gets : 该SQL在快照时间内累计运行所消耗的buffer gets,包括了consistent read 和 current read
- Executions : 该SQL在快照时间内累计执行的次数
- Gets per Exec : 该SQL平均单次的buffer gets , 对于事务型transaction操作而言 一般该单次buffer gets小于2000
- % Total 该SQL 累计运行所消耗的buffer gets占 总的db buffer gets的比率, (SQL buffer gets / DB total buffer gets)
说明:
- Physical reads : 该SQL累计运行所消耗的物理读
- Executions : 该SQL在快照时间内累计执行的次数
- Reads per Exec : 该SQL 单次运行所消耗的物理读, (SQL Physical reads/Executions) , 对于OLTP transaction 类型的操作而言单次一般不超过100
- %Total : 该SQL 累计消耗的物理读 占 该时段总的 物理读的比例, 即 ( SQL physical read / Total DB physical read )
5、表段分析
从前面整体提示IO问题,接下来我们看一下Segments by Physical Writes和Segments by Physical Write Requests,看一下哪些表段在IO方面占用比较高,发现AUDIT_LOGIN_DB这张表物理写占了20%,物理请求也占了8.2%,估计是数据量过大了
该表不属于业务表,这里判断异常在这张表上。
六、故障表分析
1、查看该表数据量及明细
这张表是属于用户登录时记录IP等信息,每次登陆触发器都会去写这张表,目前该表数据量已经到8百万级别,且从登录时间可以看到插入频率一直很高
2、减少数据量
该表无太大作用,这里选择保留一段时间后做表的切换,然后truncate,至于怎么做,前面提了N次,篇幅有限,这里就不做介绍了...
七、测试
经过一段时间测试后,业务反馈正常,问题解决,又可以打酱油了~
用户评论
这篇文章写的太棒了!我也是最近遇到数据库存储卡顿的问题,看了你的方法感觉很有启发! 我准备试一试把索引结构调整一下,希望能达到预期效果。
有19位网友表示赞同!
数据系统的优化真的考验人的功力啊,看到你分析思路清晰,对问题排查和解决步骤都非常详细,让我受益匪浅!
有6位网友表示赞同!
遇到系统卡顿确实会让人很头疼,还好有你的这篇博客记录了整个优化过程,方便其他小伙伴借鉴。我感觉数据库索引真的很重要,以后一定要多留意。
有14位网友表示赞同!
我觉得你把问题描述的很好,也很专业! 我自己也经历过这个问题,当时就找了很久解决方法,希望能再多分享一些数据库调优的小技巧!
有16位网友表示赞同!
写得真不错,很详细很到位!我最近也遇到了一种类似的问题,感觉你的这个优化实例很有帮助,感谢分享!
有15位网友表示赞同!
系统卡顿的问题确实让人糟心。我觉得你的文章非常有用,特别是那些数据库索引的调整方案,给我很多启发! 我也会试试用在自己的项目中。
有6位网友表示赞同!
我比较同意你的观点,数据库存储性能优化是需要不断学习和积累经验的,这次你分享的优化的实例案例真的很棒!
有9位网友表示赞同!
其实数据库系统设计本身就需要注意很多细节,如果一开始就能把索引结构调好,后期优化应该更容易吧? 但遇到这样的卡顿问题确实很棘手。
有12位网友表示赞同!
我想问问你的文章中提到的 "Query Optimizer" 是怎么工作的呢? 因为我对这个词感到好奇,希望能了解更多关于它 的信息!
有13位网友表示赞同!
这个例子很有用,但我觉得可以补充一些关于数据库监控和诊断工具的介绍,这对解决这类问题很有帮助!
有9位网友表示赞同!
文章内容比较专业,对数据系统优化有很好的理解。如果能针对不同类型的卡顿问题提供不同的解决方案会更加完善
有18位网友表示赞同!
我觉得你的分析很到位,特别是针对索引策略调整,我认为这是解决数据库性能瓶颈的关键之一! 这篇文章真的帮了我的忙!
有10位网友表示赞同!
其实系统卡顿问题的根源很多,除了数据库优化,还需要考虑服务器硬件配置、网络带宽等因素。
有5位网友表示赞同!
数据库优化是一个非常重要的技能,这篇文章分享的内容很有价值,值得每个人认真学习! 希望你能继续分享更多类似的干货知识!
有16位网友表示赞同!
我也遇到过类似卡顿问题,当时找解决方案耗费了大量时间精力,你的经历让我明白解决这类问题的难点在哪儿。
有17位网友表示赞同!
系统卡顿确实会导致很多用户体验下降,文章提到数据库读写性能优化很重要,我以后会更加关注这个方面的学习!
有5位网友表示赞同!
我比较赞同你文中提到的“预热数据”技巧,它可以有效缓解一部分系统的卡顿问题。 对于一些热点查询,可以提前进行预热处理!
有5位网友表示赞同!