对于一个生产系统的告警,如果我们是一个初/中级工程师的水平,我们应该如何通过
已有的知识体系,结合合理的推测与验证,找到问题的根因,最后能提出具有中/高级水平的风险提示和运维建议呢?下面我们来看老K是如何与新手同事一步一步分析的,并最终提出非常有意义的。
熟悉老K的朋友都知道老K平常很大一部分时间是待在某总行级数据中心支持日常运维工作,该总行数据中心拥有自己的DBA团队数十人,高手技术了得,但是还是新手比较多,日常的简单运维工作主要是是新手同事们去处理,希望他们从日常的运维case的处理过程中多学到一些技术知识,当然,他们在处理case的过程中没少给老K提问题,但是,在回答他们的问题过程中,老K倒是也狠狠的扎实了一把自己的知识面。
“老K,快来帮我看个SQL,这个SQL我都找不到!”在监控现场的同事又来求助了。
这是个什么问题?什么叫SQL找不到?老K先嘀咕着,很快赶到现场,稍微了解了一下,原来监控工具报某重要系统报了ORA-01555错误,需要分析一下,监控的来源是alert日志,原错误很简单;
就是一个再简单不过的报错了,sql_id是2c1fxpx8j6z9m,在alert日志中也已经打印出来了,唯一的遗憾是ORA-01555报错后面通常会有一个duration来告诉大家SQL报错前持续执行了多久。
“为什么说找不到呢,这不是sql_id都在这了吗?用我们平时说的方法查就可以了呀!”
“历史视图和AWRSQRPT都查过了,就是找不到呀。”
说着,他还给我看了一下他的查询结果:
此处用个小面板啥的~取名叫科普ORA-01555啥的
“讲的不错,就是太教条化了,就我们现在的系统来说,导致ORA-01555的可能原因在哪呢?”
“我们的系统UNDO表空间还是足够的,相关参数应该是没问题的,我们以前经常遇到的ORA-01555都是执行时间过长导致的,如果这个SQL执行时间很长的话,我肯定能在历史视图中查找到呀,那这里是不是bug或者其他原因呢?应该怎么去查呢?”
嗯,好像很有道理。一个SQL,我们在历史视图中查不到,那可不就是执行很短吗?不过老K有了上面的这些信息,对于上面的结论表示深深的不认同。
你觉得呢?不妨停下来看一看,仔细思考一下,你认同上面的结论吗?
为什么无法历史视图中查找到?
那么这两个特征能说明什么呢,有经验的朋友可能一眼就看出来了,没错,这里显然是在导出时抛出的错,在抛错完成后,导出任务也就结束了。有了这个信息之后,我们再通过相关查询以及与应用维护团队的沟通后,找到了相关导出的日志后,我们看到当天的导出日志信息:
我们可以看到,非常符合,导出时间从0点开始,到11:09结束,而且导出日志中确实也是在导出XXX_RT_DET抛出了ORA-01555错误;
“然而,它为什么没有记录在ASH视图中呢?”
“稍安勿躁,且看我慢慢道来。”
虽然我们找到了应用没有关注的导出报错的信息,也能匹配上确实报了ORA-01555错误,但似乎还是不能帮我们确认SQL执行了多长时间,我们不妨换一个思路来看这个问题;
首先,语句在手,我们不妨看看正常情况下2c1fxpx8j6z9m的执行计划是什么样的:
另一方面,我们说导出也好,或者2c1fxpx8j6z9m的执行也罢,最终访问的不还是XXX_RT_DET对象吗;查不到SQL语句,我们不妨查查都在什么时间段内访问了这个对象了,以及在这个对象上的等待事件;
“你看吧,之前的语句2c1fxpx8j6z9m应该是全表扫描,这里5m8ruy0agb6mw的等待事件是单块读,明显不一样嘛。我还是觉得,是不是导出过程中时是要通过5m8ruy0agb6mw来做,但是最后还是要另外执行2c1fxpx8j6z9m,然后报错了。”
“嗯,很有道理,对执行计划和等待事件的理解不错。不过我再看一条命令,就应该能给你一个确切的答案了。”
马上,见证奇迹的时刻就要到了……
前面因为有导出抛ORA-01555与alert中的匹配,已经可以知道语句2c1fxpx8j6z9m是在导出的过程中执行的了,但是还不能确认2c1fxpx8j6z9m和语句5m8ruy0agb6mw的关系,也就不能确认2c1fxpx8j6z9m到底执行了多长时间;
这里,我们其实已经知道了SQL的执行结束时间,但是其实,我们只需要知道SQL的开始时间,不就可以确认执行时间了吗?没错,就是这个方法;
导出表XXX_RT_DET花费了10个小时,也就是2c1fxpx8j6z9m执行了10个小时,执行时间过长,在开门营业时间内,因为联机业务对表XXX_RT_DET存在大量的DML操作,导致了ORA-01555的出现。
“PERFECT!这样看来是不是所有的问题都得到解释了。”
“可是,它的等待事件是db file sequential read呀?这个你没有解释!”
“没错,这就是我们的问题所在,正常来说,全表扫描的话,不会出现那么多db file sequential read,也就不会那么慢,我们把这个等待事件解决了,问题就也解决了!”
“太累了,我要捋一捋思路。”
到这我们来看看,我们是如何一步一步走到现在这一步的:
那么,一个全表扫描的执行计划跑出来的sql通常会有哪些情况导致db file sequential read呢?通常有几种:
简单一查就能得出结论,第一条和第二条不符合我们目前面临的情况,那我们来看看怎么定位有没有行迁移呢?其实很简单,我们收一个导出时段的AWR报告,查找关键字continued row,如下:
在了解上述情况后,我们再回头来检查应用以往的导出日志,我们还是会发现,XXX_RT_DET表的导出总是最晚的,不过并不一定报ORA-01555,不过现在ORA-01555已经并不是我们关注的重点了,因为我们已经知道,如果让导出不跑到联机时段,是不不会报ORA-01555的;而且,该表的导出偏晚并不是一个逐步的过程,是由某一天突然变化的,那么问题又来了,这又是为什么呢?
因为历史太久,数据库的历史视图已经看不到当时的变化前后的情况了,这里就需要把几种产生行迁移的可能给应用团队列出来,看看咱们的业务符合哪个特征:
“不过,增加一个字段会导致95%的块都存在行迁移的情况吗?太厉害了吧!”
“嗯,很有道理!这个我们就需要查一查了!”
不查不知道,这里简单搜一下MOS,就能看到下面的文章(截取精华部分):
这样,我们这里的根本原因,我们可以认为是两条:
其实我们看到上述案例中,行迁移导致的数据泵导出缓慢只是其中一种现象;同理,我们可以知道,如果一个表上存在大量的行迁移,可能会导致表的访问性能出现严重下降,简单来说,当SQL访问到某条记录在A块中,但是该条记录又被链接到B块,那么这时SQL访问一条记录就读取了两个块,而且,如果是类似本CASE中的全表扫描,还会出现高比例的db file sequential read等待事件的情况;所以,我们应该要规避行迁移;
如何规避行迁移:
那么,对于已有的系统,我们应该如何针对单个表来排除呢?像上文提到的使用导出时的比例统计因为bug原因可能并不准确;需要更精确的方法:
如前文所提到的,我们可以通过table fetch continued row统计值来统计表中存在行迁移的行数;具体如下:
1) 已知一个会话sid,执行下述语句:
针对目前的情况,我们的解决方案分两部分:
临时性的方案:针对XXX_RT_DET表,我们单独拎出来导出,指定导出的access_method为external_table模式,避免再出现导出时间非常长的情况,进而避免ORA-01555的情况;但是该方案只能是针对导出的。
根本性解决方案:针对XXX_RT_DET表,及检查到的类似的表,通过DBMS_REDEFINITION的包重定义表,消除行迁移;其他表如果存在日常业务大量导致字段长度变长的update操作,在重定义时,增加表的pct_free值。
目前,该表已经重定义完成,完成后表的大小变化不多,但是导出已经从10个小时下降到十几分钟。
如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!
赞0
添加新评论0 条评论