> 文档中心 > Oracle-enq:TX-row-contention等待场景

Oracle-enq:TX-row-contention等待场景

​前言:

产生TX锁等待的原因一般都是应用程序的逻辑问题,表,索引设计问题以及性能问题导致,本文主要讨论TX锁的等待产生场景

等待场景:

1 应用代码逻辑层设计问题导致同时修改相同数据引发锁等待。

2 事务没有正常commit/rollback引发锁等待。

3 主键或者唯一键冲突引发锁等待。

4 位图索引引发锁等待。

5 大事务回滚导致的锁等待。

6 慢SQL导致的锁等待。

7 查询包含事务调用导致的锁等待。

表数据:

table_name:test.test_1 SQL> desc test.test_1; Name      Null?    Type ----------------------------------------- -------- ---------------------------- ID      NOT NULL NUMBER(13) NAME1  VARCHAR2(30) NAME2  VARCHAR2(30) NAME3  VARCHAR2(30) STATUS VARCHAR2(2) primary key(id) bitmap index(status)   ID NAME1NAME2 NAME3 STATUS----------  ------------------------------ ------------------------------ ------------------------------ --   1 1aaaaaa 1bbbbbbbbb1ccccccccc      1   2 2aaaaaa 2bbbbbbbbb2ccccccccc      0   3 3aaaaaa 3bbbbbbbbb3ccccccccc      0   4 4aaaaaa 4bbbbbbbbb4ccccccccc      0   5 5aaaaaa 5bbbbbbbbb5ccccccccc      1

场景一:应用代码逻辑层设计问题导致同时修改相同数据引发锁等待。

session:sid:32

#执行一条update,更新id=1的数据SQL> update test.test_1set name1='1bbbb'where id=1;  ​1 row updated

session:sid:45

#执行一条update,更新id=1的数据#会话45执行被会话32堵塞,TX锁级别为6SQL> update test.test_1set name1='2bbbb'where id=1; ---->blocking​BLOCKING_STATUS--------------------------------------------------------------------------------TEST@rac1 ( SID=32 )  is blocking SYS@rac1 ( SID=45 )

有时还会引发死锁问题

session:sid:32

#执行一条update,更新id=2的数据SQL> update test.test_1set name1='2bbbb'where id=2; ​1 row updated.

session:sid:45

#执行一条update,更新id=1的数据SQL> update test.test_1set name1='1bbbb'where id=1;​1 row updated.

session:sid:32

#执行一条update,更新id=1的数据#会话32执行被会话45堵塞,TX锁级别为6SQL> update test.test_1set name1='1aaaa'where id=1;---->blocking​BLOCKING_STATUS--------------------------------------------------------------------------------SYS@rac1 ( SID=45 )  is blocking TEST@rac1 ( SID=32 )​

session:sid:45

#执行一条update,更新id=2的数据#会话45执行被会话32堵塞,TX锁级别为6SQL> update test.test_1set name1='2bbbb'where id=2;---->blocking​BLOCKING_STATUS--------------------------------------------------------------------------------TEST@rac1 ( SID=32 )  is blocking SYS@rac1 ( SID=45 )

session:sid:32

#此时会话32报00060死锁错误,执行的sql被回滚但事务并没回滚SQL> update test.test_1set status=0where id=1; update test.test_1     *ERROR at line 1:ORA-00060: deadlock detected while waiting for resource

场景二:事务没有正常commit/rollback引发锁等待。

1 会话出现超时导致死链接,导致事务无法正常提交。

2 代码逻辑设计出现问题导致没有完成commit/rollback流程,特别是在对一些异常捕获的流程处理。

3 数据库性能问题,bug导致的无法正常commit/rollback。

场景三:主键或者唯一键冲突引发锁等待。

session:sid:32

#会话32插入一条主键为6的数据insert into test.test_1 values(6,'6aaaaaa','6bbbbbbb','6ccccccc',0);​1 row created.

session:sid:45

#会话45也插入一条主键为6的数据#会话45执行被会话32堵塞,TX锁级别为4insert into test.test_1 values(6,'6aaaaaa','6bbbbbbb','6ccccccc',0);---->blockingBLOCKING_STATUS--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------TEST@rac1 ( SID=32 )  is blocking SYS@rac1 ( SID=45 )​   INST_ID    SID TY  ID1     ID2 OWNER OBJECT_NAME    LMODE    REQUEST---------- ---------- -- ---------- ---------- -------------------- ---------------------------------------- ---------- ----------   1     32 TX     720926    29326    0   1     32 TM      880600 TEST TEST_1  3    0   1     45 TX     983040    23396    0   1     45 TM      880600 TEST TEST_1  3    0   1     45 TX     720926    29320    4​

需要等到会话32提交了事务,会话45才会报唯一键冲突。

ERROR at line 1:ORA-00001: unique constraint (TEST.SYS_C0011112) violated

场景四:位图索引引发锁等待。

session:sid:32

#会话32更新表test_1 id=1的数据SQL> update test.test_1     set status=2     where id=1;     1 row updated.​

session:sid:45

#会话45更新test_1 id=2的数据#会话45执行被会话32堵塞,TX锁级别为4SQL> update test.test_1  2  set status=3  3  where id=2;---->blockingBLOCKING_STATUS---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------TEST@rac1 ( SID=32 )  is blocking SYS@rac1 ( SID=45 )​   INST_ID    SID TY  ID1     ID2 OWNER OBJECT_NAME    LMODE    REQUEST---------- ---------- -- ---------- ---------- -------------------- ---------------------------------------- ---------- ----------   1     32 TX    1114133    4282   6    0   1     32 TM      880600 TEST TEST_1     3    0   1     45 TX    1179656    2547   6    0   1     45 TM      880600 TEST TEST_1     3    0   1     45 TX    1114133    4282

由于位图索引使用位图来记录数据,不同的DML更新不同的行可能争用同一段位图段,所以会产生锁等待。

场景五:大事务回滚导致的锁等待。

session:sid:55

#会话55更新表test_1 id=2的2百万数据SQL> update test.test_1set name1='aaaaaaaaaaa'where id=2;#从操作系统kill了会话55,让会话55事务进行回滚kill -9 15699​ERROR at line 1:ORA-03135: connection lost contactProcess ID: 15699Session ID: 55 Serial number: 3

session:sid:29

#会话29更新表test_1 id=2数据#会话55执行被会话29堵塞,TX锁级别为6update test.test_1set name1='xxx'where id=2 and rownumblockingBLOCKING_STATUS---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------TEST@rac1 ( SID=55 )  is blocking SYS@rac1 ( SID=29 )#堵塞的会话正是当前正在回滚的事务INST_ID ADDR  XIDUSN    XIDSLOT     XIDSQN     UBAFIL   UBABLK     UBASQN     UBAREC STATUS  START_TIME      START_SCNB START_SCNW START_UEXT START_UBAFIL START_UBABLK START_UBASQN START_UBAREC SES_ADDR    FLAG SPA REC NOU PTX------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ---------- ---------- ------------ ------------ ------------ ------------ ---------------- ---------- --- --- --- ---NAME   PRV_XIDUSN PRV_XIDSLT PRV_XIDSQN PTX_XIDUSN PTX_XIDSLT PTX_XIDSQN     DSCN-B    DSCN-W  USED_UBLK  USED_UREC     LOG_IO     PHY_IO   CR_GET---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- CR_CHANGE START_DAT  DSCN_BASE  DSCN_WRAP  START_SCN DEPENDENT_SCN XID PRV_XID PTX_XID---------- --------- ---------- ---------- ---------- ------------- ---------------- ---------------- ----------------      1 000000007E907E60   17      144285     5    49614 885     66 ACTIVE  05/19/22 18:28:085967266    0     0  5   226    751 40 00000000827AABC8  7683 NO  NO  NO  NO    00    0     0 0    0      0  0      43346    4194304   12749349      73104  2185496   2092747 19-MAY-22 0    0    5967266      0 11000E00BD100000 0000000000000000 0000000000000000​

场景六:慢SQL导致的锁等待。

1 事务里面包含多个执行sql或者存在慢SQL导致提交时间延长。

#执行一条update,更新id=1的数据,并执行数据查询#这时候数据查询的速度会直接影响事务的提交速度,如果查询过慢,就可能出现锁等待的情况SQL> update test.test_1set name1='1bbbb'where id=1;SQL> select count(*) from test.test_2 where object_id=1;​

2 自身DML操作语句执行效率过低,如全表扫描,或者多表关联操作。

场景七:查询包含事务调用导致的锁等待。

#创建一个带匿名事务的函数create or replace function fun_test return varchar2aspragma autonomous_transaction;begin  update test.test_1  set name1='aaa'  where id='6';  commit;  return 1;end;/

session:sid:52

#会话52执行带函数的查询select fun_test from dual;

session:sid:29

#会话29执行update id=6#会话29执行被会话52堵塞,TX锁级别为6,直到会话52执行语句结束update test.test_1set name1='xxx'where id=6 and rownumblockingBLOCKING_STATUS--------------------------------------------------------------------------------TEST@rac1 ( SID=52 )  is blocking SYS@rac1 ( SID=29 )

网赚站