Oracle等待事件队列等待之TX - allocate ITL entry引起的死锁处理

0    347    1

Tags:

👉 本文共约9735个字,系统预计阅读时间或需37分钟。

前言部分

导读和注意事项

各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~:

① enq: TX - allocate ITL entry等待事件的解决

② 一般等待事件的解决办法

③ 队列等待的基本知识

④ ITL死锁解决

⑤ ITL死锁模拟

⑥ Merge语句的非关联形式的查询优化

故障分析及解决过程

故障环境介绍

项目source db
db 类型RAC
db version11.2.0.3.0
db 存储ASM
OS版本及kernel版本AIX 64位 7.1.0.0

故障发生现象及故障分析解决

早上刚来上班,同事就发了一个SQL过来,说是有锁,然后我就查了查系统里的锁,结果一个锁都没得。好吧,还是得干点事的,先看看SQL语句:

MERGE INTO TLHR.TLHRBOKBAL S

USING (SELECT A.BOOKACCOUNT AS BOOKACCOUNT,

(A.CURRBALANCE + NVL(B.BAL, 0.00)) AS BANKAMT

FROM TLHR.TLHRBOKBAL_TMP A,

(SELECT T1.BOOKACCOUNT AS BOOKACCOUNT,

SUM(DECODE(T1.DCFLAG, 'D', -T1.AMT, 'C', T1.AMT, 0)) AS BAL

FROM TLHR.TLHRBOKBALJN T1

WHERE T1.BOOKACCOUNT LIKE '13500000%'

AND T1.TRANDATE = '20150901'

AND (T1.REASON IN ('1', '2') OR

(T1.REASON = '0' AND T1.ONLINEFLAG = '1'))

GROUP BY T1.BOOKACCOUNT) B

WHERE A.BOOKACCOUNT = B.BOOKACCOUNT(+)

AND A.BOOKACCOUNT LIKE '13500000%') T

ON (S.BOOKACCOUNT = T.BOOKACCOUNT)

WHEN MATCHED THEN

UPDATE

SET S.LASTBALANCE = T.BANKAMT,

S.CURRBALANCE = T.BANKAMT,

S.DEBITAMT = 0.00,

S.CREDITAMT = 0.00;

看起来是一个MERGE语句,按照小麦苗以前的经验,这一类的SQL最好是修改为MERGE的非关联形式比较好,我们先看看执行计划有没有问题:

先找到SQL_ID为53qv858pwwwwb:

SELECT a.ELAPSED_TIME,a.EXECUTIONS,a.* FROM v$sql a WHERE a.SQL_TEXT LIKE '%MERGE INTO TLHRBOKBAL S%' AND A.SQL_TEXT LIKE '%13500000%' ;

查询历史执行计划:

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR(SQL_ID => '53qv858pwwwwb' )) ;

可以看到,该执行计划的顺序为【7-->6-->5-->4-->9-->10-->8-->3-->2-->1-->0】,而耗费性能的地方在9、10、8这3个步骤上,走的是全表扫描,我们先看看2个大表的数据量:

SELECT COUNT(*) FROM TLHR.TLHRBOKBAL_TMP A WHERE A.BOOKACCOUNT LIKE '13500000%'; --306043/38998765

SELECT COUNT(*) FROM TLHR.TLHRBOKBAL A WHERE A.BOOKACCOUNT LIKE '13500000%'; --306043/38826275

从3000万的数据里边取出30万的数据,还是比较少的,所以应该去走索引的,看了一下统计信息,也是最新收集的,好吧,算了,先修改一下SQL让其走索引扫描看看,:

MERGE INTO TLHR.TLHRBOKBAL S

USING (SELECT S.ROWID ROWIDS,

A.BOOKACCOUNT AS BOOKACCOUNT,

(A.CURRBALANCE + NVL(B.BAL, 0.00)) AS BANKAMT

FROM (SELECT /*+index(NB,PK_TLHRBOKBAL_TMP)*/NB.CURRBALANCE,NB.BOOKACCOUNT

FROM TLHR.TLHRBOKBAL_TMP NB

WHERE NB.BOOKACCOUNT LIKE '13500000%') A,

TLHR.TLHRBOKBAL S,

(SELECT T1.BOOKACCOUNT AS BOOKACCOUNT,

SUM(DECODE(T1.DCFLAG, 'D', -T1.AMT, 'C', T1.AMT, 0)) AS BAL

FROM TLHR.TLHRBOKBALJN T1

WHERE T1.BOOKACCOUNT LIKE '13500000%'

AND T1.TRANDATE = '20150901'

AND (T1.REASON IN ('1', '2') OR

(T1.REASON = '0' AND T1.ONLINEFLAG = '1'))

GROUP BY T1.BOOKACCOUNT) B

WHERE A.BOOKACCOUNT = B.BOOKACCOUNT(+)

AND S.BOOKACCOUNT = A.BOOKACCOUNT

AND S.BOOKACCOUNT LIKE '13500000%') T

ON (T.ROWIDS = S.ROWID)

WHEN MATCHED THEN

UPDATE

SET S.LASTBALANCE = T.BANKAMT,

S.CURRBALANCE = T.BANKAMT,

S.DEBITAMT = 0.00,

S.CREDITAMT = 0.00

执行计划中,基本都走了索引了,跑了一下,大约1分种多,但是里边有个HINTS,分析了一下表TLHRBOKBAL_TMP上的索引情况,发现是个主键索引,且有2个列(BOOKACCOUNT,CURRENCY),但是不包含列CURRBALANCE,可能是Oracle觉得回表读的耗费比较大吧,那这里可以使用虚拟索引测试一下索引的性能:

CREATE INDEX IX_VI01_ID ON TLHR.TLHRBOKBAL_TMP(CURRBALANCE, CURRENCY,BOOKACCOUNT) NOSEGMENT;

ALTER SESSION SET "_USE_NOSEGMENT_INDEXES"=TRUE;

EXPLAIN PLAN FOR MERGE INTO TLHR.TLHRBOKBAL S

USING (SELECT S.ROWID ROWIDS,

A.BOOKACCOUNT AS BOOKACCOUNT,

(A.CURRBALANCE + NVL(B.BAL, 0.00)) AS BANKAMT

FROM (SELECT NB.CURRBALANCE,NB.BOOKACCOUNT

FROM TLHR.TLHRBOKBAL_TMP NB

WHERE NB.BOOKACCOUNT LIKE '13500000%') A,

TLHR.TLHRBOKBAL S,

(SELECT T1.BOOKACCOUNT AS BOOKACCOUNT,

SUM(DECODE(T1.DCFLAG, 'D', -T1.AMT, 'C', T1.AMT, 0)) AS BAL

FROM TLHR.TLHRBOKBALJN T1

WHERE T1.BOOKACCOUNT LIKE '13500000%'

AND T1.TRANDATE = '20150901'

AND (T1.REASON IN ('1', '2') OR

(T1.REASON = '0' AND T1.ONLINEFLAG = '1'))

GROUP BY T1.BOOKACCOUNT) B

WHERE A.BOOKACCOUNT = B.BOOKACCOUNT(+)

AND S.BOOKACCOUNT = A.BOOKACCOUNT

AND S.BOOKACCOUNT LIKE '13500000%') T

ON (T.ROWIDS = S.ROWID)

WHEN MATCHED THEN

UPDATE

SET S.LASTBALANCE = T.BANKAMT,

S.CURRBALANCE = T.BANKAMT,

S.DEBITAMT = 0.00,

S.CREDITAMT = 0.00;

SELECT * FROM TABLE(DBMS_XPLAN.display);

说明创建3个列的索引是可以的。我们先将该虚拟索引删除DROP INDEX IX_VI01_ID;

ITL死锁问题解决

另外一个问题,是开发说上边的SQL语句产生了死锁,起初我还半信半疑,先去告警日志中用命令(more alert* | grep Deadlock)搜了一下:

结果发现很多的死锁,拿到相关的文件,看到如下一段:

果然,产生死锁的SQL还是上边分析优化的SQL,其中会话信息为:(332,47221),我们去DBA_HIST_ACTIVE_SESS_HISTORY视图里查询:

SELECT D.SQL_ID, D.CURRENT_OBJ#, D.EVENT, COUNT(1)

FROM DBA_HIST_ACTIVE_SESS_HISTORY D

WHERE D.SAMPLE_TIME BETWEEN

TO_DATE('2016-09-01 18:25:00', 'YYYY-MM-DD HH24:MI:SS') AND

TO_DATE('2016-09-01 18:45:00', 'YYYY-MM-DD HH24:MI:SS')

AND D.BLOCKING_SESSION_STATUS = 'VALID'

AND D.SESSION_ID = 332

本人提供Oracle(OCP、OCM)、MySQL(OCP)、PostgreSQL(PGCA、PGCE、PGCM)等数据库的培训和考证业务,私聊QQ646634621或微信dbaup66,谢谢!
AiDBA后续精彩内容已被站长无情隐藏,请输入验证码解锁本文!
验证码:
获取验证码: 请先关注本站微信公众号,然后回复“验证码”,获取验证码。在微信里搜索“AiDBA”或者“dbaup6”或者微信扫描右侧二维码都可以关注本站微信公众号。

标签:

Avatar photo

小麦苗

学习或考证,均可联系麦老师,请加微信db_bao或QQ646634621

您可能还喜欢...

发表回复