墨墨导读:业务卡顿异常,有几个 insert into 语句的gc等待比较严重,发生业务超时,本文分析了超时原因并详述整个处理过程,希望对大家有帮助。

1. 故障现象

客户报2020年7月9号,8点30分左右业务卡顿异常,有几个 insert into 语句的gc等待比较严重,发生业务超时,需要紧急分析一下超时原因,并给出处理建议。

2. AWR分析

由于是业务卡顿分析,可以让客户配合出各节点实例的awr报告辅助分析,另一方面同时进行分析ASH信息:

可以看到gc等待排第一位,等待次数异常高。

可以看到gc等待主要是由3个insert into语句产生的。

3. 诊断分析及建议

首先先备份ASH表,避免数据被刷出内存:

from gv$active_session_historywhere sample_time >=to_date('2020-07-09 08:00:00', 'yyyy-mm-dd hh24:mi:ss')and sample_time <to_date('2020-07-09 10:00:00', 'yyyy-mm-dd hh24:mi:ss')

其次查询各实例按分为统计单位的等待次数趋势情况:

可以发现实例1并没有等待暴增的情况,而实例2在8:30时等待暴示,进一步查询实例2等待次数变化情况:

  from gv$active_session_historywhere sample_time >=to_date('2020-07-09 08:00:00', 'yyyy-mm-dd hh24:mi:ss')and sample_time <to_date('2020-07-09 10:00:00', 'yyyy-mm-dd hh24:mi:ss')and event is not nulland inst_id=1group by eventorder by 2 desc;

可以看到确实是节点2的GC等待很严重。

进一步查询gc等待严重的sql语句是哪些:

可以看到这三个gc等待严重的SQL语句都是insert into语句,且是插入同一个表。这里和AWR的分析相吻合,进一步查询gc使用块类型占比,考虑如果被用于撤销块比例过多,则应用实例划分可以大大降低GC传输。

  trunc(data_requests / decode(tot_req,0,1), 2) * 100 data_per,  --data blockstrunc(undo_requests / decode(tot_req,0,1), 2) * 100 undo_per,  --undo blockstrunc(tx_requests / decode(tot_req,0,1), 2) * 100 tx_per,      --undo header blockstrunc(other_requests / decode(tot_req,0,1), 2) * 100 other_per --other blocksfrom (select inst_id,cr_requests + current_requests tot_req,data_requests,undo_requests,tx_requests,other_requestsfrom gv$cr_block_server)order by inst_id;

这里除了看到数据块的CR块GC传输比较多,也可以看到undo header的cr块传输占比也很大。进一步查询gc buffer busy acquire等待按块类型分类情况:

 (select *from (select /*+ materialize */inst_id,event,current_obj#,current_file#,current_block#,count(*) cntfrom gv$active_session_historywhere event = 'gc buffer busy acquire'group by inst_id,event,current_obj#,current_file#,current_block#having count(*) > 5)where rownum < 101)
select *from (select inst_id,owner,object_name,object_type,current_file#,current_block#,cntfrom ash_gc a, dba_objects owhere (a.current_obj# = o.object_id(+))and a.current_obj# >= 1unionselect inst_id,'','','Undo Header/Undo block',current_file#,current_block#,cntfrom ash_gc awhere a.current_obj# = 0unionselect inst_id,'','','Undo Block',current_file#,current_block#,cntfrom ash_gc awhere a.current_obj# = -1)order by 7 desc

可以看到Undo Header/Undo block的统计次数最大,最严重的GC等待来自undo上的数据块,验证了前面cr块的gc传输很大的情况。由于都是同一个表的gc传输,这时客户开发反馈,昨晚有业务处理

 set a.subpayway ='05'where exists (select 1 from t1_20200708 b where a.bizfeedetid = a.bizfeedetid);

但中间杀了没提交,写入表慢是否跟这个有关?
根据这个信息,怀疑是这个UPDATE语句的表数据量很大,执行非常慢才去杀掉的,客户回复可能是没有写好条件,这个SQL等于是更新了整张表,确实是中止了,进行异常回滚而没有正常提交。从SQL写法上(a.bizfeedetid = a.bizfeedetid)也可以看到恒等的错误,查看这个表数据量:

这个表不是分区表,数据量达到6亿多条,update全表根本无法完成。
分析gc buffer busy acquire等待事件:

这里可以知道gc buffer busy acquire等待需等待lgwr刷新未提交的变更到日志中,也就需要undo的回滚和一致性要求,根据以往的经验,如果如果lgwr写入慢,则会进一步加重在gc的等待,进一步查看lgwr 的 trace,发现写抖动严重:

节点1、节点2,也就是实例1、实例2的lgwr写入都存在写入延迟的问题,lgwr写入抖动很严重,2KB都要写516ms,lgwr写入慢,如果碰上大量的gc块获取,就会产生大量的gc等待,这里lgwr刷新需求和lgwr写入慢相应验证插入业务卡顿的故障现象。

继续查log file parallel write直方图:

同样验证log写入有比较严重的抖动现象。

可通过v$fast_start_transactions视图查看正在回滚的事务:

根据XID事务ID已经找不到对应事务了,只有之前完成的回滚。

查询到这条update只在节点1执行,且最后一次执行时间是在09:59分,此时已经11点了,没有查到回滚事务信息,说明已经完成了事务回滚,故障已自动恢复。这里客户反馈库这时latch: cache buffers chains等待严重,查询此时的等待链信息:

with ash as(select /*+ materialize*/*from gv$active_session_history twhere sample_time >=to_date('2020-07-09 11:00:00', 'yyyy-mm-dd hh24:mi:ss')and sample_time <to_date('2020-07-09 12:00:00', 'yyyy-mm-dd hh24:mi:ss')),
chains as(select inst_id,blocking_session blocking_sid,blocking_session_serial#  blocking_serial,session_id,session_serial# session_serial,level lvl,sys_connect_by_path(inst_id||' '||session_id || ',' || session_serial# || ' ' ||sql_id || ' ' || event,' <-by ') path,connect_by_isleaf isleaffrom ashstart with event in ('latch: cache buffers chains')connect by nocycle(prior blocking_session = session_idand prior blocking_session_serial# = session_serial#and prior sample_id = sample_id))
select inst_id,blocking_sid,blocking_serial,lpad(round(ratio_to_report(count(*)) over() * 100) || '%', 5, ' ') "%This",count(*) ash_time,pathfrom chainswhere isleaf = 1group by inst_id,blocking_sid,blocking_serial, pathorder by inst_id,ash_time desc;

依然是之前一个那个没有分区的6亿条记录表的一条insert语句,只是等待事件由gc变成cbc等待,根据以往处理经验,CBC的等待需要考虑BUFFER不够和访问热点的问题,需要从表结构、表参数、索引设计、索引参数等考虑优化。

客户反馈这个表是一些中间数据,分区标识不明显,所以一直没有进行分区,且对查询要求比较高,还会和三个同等大小的表关联。

针对这种情况,我们给出建议是创建成全局HASH分区表可能较合适的,索引也相应创建成分区索引,需要根据业务再讨论设计。可以先设置pctfree参数缓解CBC。

综合以上的分析,可以确认本次故障是由于开发一条update语句条件错误导致大量的undo事务回滚,使在另一实例上的相同表的几个业务上insert into语句产生大量的gc buffer busy acquire等待,加上lgwr写入抖动加剧了等待时长,最终引起了前台业务卡顿。

4. 故障总结

一个update语句写法错误就导致了整个业务系统的务卡顿,说明对大表的DML/DDL操作需要更加慎重,大表操作更加容易导致故障发生,如果语句错误需要及时发现,更早时间介入处理,以避免长时间造成的业务卡顿。

针对本次故障,给予以下几个建议:

  1. 应用上要尽量避免这样的操作异常造成的大量回滚,针对大表的DML/DDL操作需要更加慎重。

  2. 为尽量避免GC等待,可以考虑进行应用划分,某个业务功能限制在一个节点中执行。

  3. log file parallel write日志写入有严重的延迟,需要存储厂商配合进一步分析。

  4. 当前大表建议改造为全局HASH分区表可能更合适,索引也相应创建成分区索引,需要根据业务再讨论设计。可以先设置pctfree参数缓解CBC。

墨天轮原文链接:https://www.modb.pro/db/27542(复制到浏览器中打开或者点击“阅读原文”)

推荐阅读:144页!分享珍藏已久的数据库技术年刊

数据和云

ID:OraNews

如有收获,请划至底部,点击“在看”,谢谢!

点击下图查看更多 ↓

云和恩墨大讲堂 | 一个分享交流的地方

长按,识别二维码,加入万人交流社群

请备注:云和恩墨大讲堂

  点个“在看”

你的喜欢会被看到❤

警示:一个update语句引起大量gc等待和业务卡顿相关推荐

  1. 把我坑惨的一个update语句!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:ju.outofmemory.cn/entry/336774 ...

  2. mysql 一个update语句 对主表内容和子表批量修改

    1. (附加内容:什么时候复写equals和hashCode,为什么有的人不喜欢用lombock) 在开发中,经常会遇到 修改一张主表的数据后,然后再去修改字表的内容,一般是调用两个sql 下面的例子 ...

  3. 相同update语句在MySQL,Oracle的不同表现(r12笔记第30天)

    今天有个朋友问我一个SQL问题,大体是一个update语句,看起来逻辑没有问题,但是执行的时候却总是报错. 语句和报错信息为: UPDATE payment_data rr    SET rr.pen ...

  4. mysql更新代码_mysql update语句的用法

    1.    单表的UPDATE语句: UPDATE [LOW_PRIORITY] [IGNORE] tbl_name SET col_name1=expr1 [, col_name2=expr2 .. ...

  5. java sql update用法_使用if else条件将SQL UPDATE语句转换为php(codeigniter)

    condition 3: a. LAMA 和 ESTIMASI 均为空 . b. LAMA 为空 c. ESTIMASI 为空 如果要根据 LAMA 和 ESTIMASI 的值更新表中的所有行,可以使 ...

  6. mysql update set_mysql update语句的用法详解

    本文详细介绍了,mysql中update语句的用法,系统全面的学习下update更新语句的用法,有需要的朋友可以参考下 首先,单表的UPDATE语句: UPDATE [LOW_PRIORITY] [I ...

  7. mysql update用法_mysql update语句的用法详解

    首先,单表的UPDATE语句: UPDATE [LOW_PRIORITY] [IGNORE] tbl_name SET col_name1=expr1 [, col_name2=expr2 ...] ...

  8. oracle:一个update修改两张表

    需求:用一个update语句修改两张表? 思路:用触发器来解决 触发器代码: 表a:table_a,表b:table_b,其中表b里面有表a的id,这个触发器意思是当修改表a的最后修改人:table_ ...

  9. mysql更新语句用法_MySQL update 语句的正确用法

    以下的文章主要介绍的MySQL update 语句的实际用法,我们首先是以单表的UPDATE语句来引出实现MySQL update 语句的实际方案,以下就是文章的详细内容描述,望你看完之后会有收获. ...

最新文章

  1. jQurey 的选择器
  2. GET_GLOBALS_FROM_SLVC_FULLSCR
  3. Simulink中DPCM量化和编码仿真
  4. selenium:反反爬拖动验证码
  5. gdal java api_Java使用GDAL库
  6. 面对微信小程序的威胁,支付宝可以考虑安心做B2C的社交了
  7. 摆摊神器五菱荣光爆红后,上汽大通房车又成夜市新晋网红
  8. 自己用过最好用的pdf转word软件
  9. Multisim 14元件伏安特性测量
  10. 反垄断重锤字节跳动,投资业务原地熄火 腾讯阿里争做“普通公司”
  11. PIC单片机入门教程(四)—— 第一个工程
  12. JVM(四).Class 文件结构(附字节码完整解析)
  13. 有趣的微分方程传之可分离变量的微分方程
  14. 鹿晗关晓彤公布恋情阿里云服务器救场 这位微博程序员新婚还加班
  15. 宝塔 nginx配置 wss
  16. C语言——函数的一些基本概念
  17. AndroidStudio开启debug调试模式
  18. IOT Core-设备接入网关
  19. Centos 6.9 Install dubbokeeper
  20. Activiti6.0 (三)核心API

热门文章

  1. cryengine开源了吗_Linux上的CryEngine支持,将开源带入厨房等
  2. JavaScript闭包详解
  3. Bootstrap列表组堆叠
  4. es6 Class 表达式
  5. java虚拟机标志_《Java虚拟机原理图解》1.3、class文件中的访问标志、类索引、父类索引、接口索引集合...
  6. 一 前端基础,http协议,form表单
  7. linux上jar包的运行
  8. 前端自动化工具gulp入门基础
  9. Ubuntu 出现 Invalid operation update 或 Invalid operation upgrade的解决办法
  10. nyoj 聪明的kk