当前位置:Gxlcms > 数据库问题 > ORACLE等待事件:enq: TX - row lock contention

ORACLE等待事件:enq: TX - row lock contention

时间:2021-07-01 10:21:17 帮助过:29人阅读

> create table test
  2  (  id number(10), 
  3     name varchar2(16)
  4  ) ;
 
Table created.
 
SQL> insert into test
  2  values(1001, ‘kk‘);
 
1 row created.
 
SQL> insert into test
 values(1002, ‘tttt‘)
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> 

 

 

会话1(会话ID为75)更新某一行

 

SQL> select sid from v$mystat where rownum =1;
 
       SID
----------
        75
 
SQL> update test set name=‘ken‘ where id=1001;
 
1 row updated.
 
SQL> 

 

会话2(会话ID为200)也更新这一行(删除亦可)

 

 
SQL> select sid from v$mystat where rownum=1;
 
       SID
----------
       200
 
SQL> update test set name=‘kerry‘ where id=1001;  --一直被阻塞

 

在会话3中查看对应的会话、锁以及等待相关信息,这些SQL各

SQL> col type for a32;
SQL> SELECT sid,      
  2         type,     
  3         id1,      
  4         id2,      
  5         lmode,    
  6         request   
  7  FROM   v$lock    
  8  WHERE  type = ‘TX‘; 
 
       SID TYPE                                    ID1        ID2      LMODE    REQUEST
---------- -------------------------------- ---------- ---------- ---------- ----------
       200 TX                                   655385       2361          0          6
        75 TX                                   655385       2361          6          0
 
SQL> COL event FOR a36; 
SQL> SELECT sid, 
  2         Chr(Bitand(p1, -16777216) / 16777215) 
  3         || Chr(Bitand(p1, 16711680) / 65535) "name", 
  4         ( Bitand(p1, 65535) )                "mode", 
  5         event, 
  6         sql_id, 
  7         final_blocking_session 
  8  FROM   v$session 
  9  WHERE  event LIKE ‘enq%‘; 
 
       SID name           mode EVENT                                SQL_ID        FINAL_BLOCKING_SESSION
---------- -------- ---------- ------------------------------------ ------------- ----------------------
       200 TX                6 enq: TX - row lock contention        cz4tvs78skhus                     75
 
SQL> COL wait_class FOR A32;  
SQL> SELECT inst_id, 
  2         blocking_session, 
  3         sid, 
  4         serial#, 
  5         wait_class, 
  6         seconds_in_wait 
  7  FROM   gv$session 
  8  WHERE  blocking_session IS NOT NULL 
  9  ORDER  BY blocking_session;
 
   INST_ID BLOCKING_SESSION        SID    SERIAL# WAIT_CLASS                       SECONDS_IN_WAIT
---------- ---------------- ---------- ---------- -------------------------------- ---------------
         1               75        200      12230 Application                                  179
 
SQL> COL TX FOR A24;
SQL> SELECT 
  2     sid, seq#, state, seconds_in_wait,
  3     ‘TX-‘||lpad(ltrim(p2raw,‘0‘),8,‘0‘)||‘-‘||lpad(ltrim(p3raw,‘0‘),8,‘0‘) TX,
  4     trunc(p2/65536)      XIDUSN,
  5     trunc(mod(p2,65536)) XIDSLOT,
  6     p3                   XIDSQN
  7    FROM v$session_wait 
  8   WHERE event=‘enq: TX - row lock contention‘;
 
       SID       SEQ# STATE               SECONDS_IN_WAIT TX                           XIDUSN    XIDSLOT     XIDSQN
---------- ---------- ------------------- --------------- ------------------------ ---------- ---------- ----------
       200         46 WAITING                         203 TX-000A0019-00000939             10         25       2361
 
SQL> col event for a36 
SQL> col username for a10 
SQL> col sql_fulltext for a80 
SQL> SELECT g.inst_id, 
  2         g.sid, 
  3         g.serial#, 
  4         g.event, 
  5         g.username, 
  6         g.sql_hash_value, 
  7         s.sql_fulltext 
  8  FROM   gv$session g, 
  9         v$sql s 
 10  WHERE  g.wait_class = ‘Application‘ 
 11         AND g.sql_hash_value = s.hash_value;
 
   INST_ID        SID    SERIAL# EVENT                          USERNAME   SQL_HASH_VALUE SQL_FULLTEXT
---------- ---------- ---------- ----------------------------- -----------  ------------- ---------------------------------
         1        200      12230 enq: TX - row lock contention    TEST       3515433816   update test set name=‘kerry‘ where id=1001
 
SQL> col type for a12;
SQL> select /*+rule*/
  2         inst_id,
  3         decode(request, 0, ‘holder‘, ‘waiter‘) role,
  4         sid,
  5         type,
  6         request,
  7         lmode,
  8         block,
  9         ctime,
 10         id1,
 11         id2
 12  from gv$lock            
 13  where (id1, id2, type) in            
 14                  (select id1, id2, type from gv$lock where request >0)
 15  order by ctime desc ,role; 
 
   INST_ID ROLE          SID TYPE            REQUEST      LMODE      BLOCK      CTIME        ID1        ID2
---------- ------ ---------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
         1 holder         75 TX                    0          6          1        255     655385       2361
         1 waiter        200 TX                    6          0          0        245     655385       2361

技术分享

 

此时只能等待持有锁的会话commit或者rollback。 通常为会话1在某行上执行 update/delete 未提交,会话2对同一行数据进行 update/delete,或其它原因(例如SQL性能差)造成的锁释放速度缓慢或网络问题,都会造成后续的会话进入队列等待。

 

2Waits due to Unique or Primary Key Constraint Enforcement

表上存在主键或唯一索引,会话1插入一个值(未提交),会话2同时或随后也插入同样的值;会话提交后1,enq: TX - row lock contention消失。

SQL> drop table test purge;
 
Table dropped.
 
SQL> create table test                                    
  2  (
  3     id  number(10), 
  4     name varchar(16), 
  5     constraint pk_test primary key(id)
  6  );
 
Table created.

 

 

会话1(会话ID为8)

SQL> insert into test values(1000, ‘kerry‘);
 
1 row created.

 

会话2(会话ID为14)

SQL> insert into test values(1000,‘jimmy‘);

会话3 在会话3中查看对应的会话、锁、以及等待信息

SQL> col type for a32;
SQL> SELECT sid,      
  2         type,     
  3         id1,      
  4         id2,      
  5         lmode,    
  6         request   
  7  FROM   v$lock    
  8  WHERE  type = ‘TX‘;   
 
       SID TYPE                                    ID1        ID2      LMODE    REQUEST
---------- -------------------------------- ---------- ---------- ---------- ----------
        14 TX                                   589835       2213          0          4
        14 TX                                   393232       2160          6          0
         8 TX                                   589835       2213          6          0
 
SQL> col event for a40 
SQL> col username for a10 
SQL> col sql_fulltext for a80 
SQL> SELECT g.inst_id, 
  2         g.sid, 
  3         g.serial#, 
  4         g.event, 
  5         g.username, 
  6         g.sql_hash_value, 
  7         s.sql_fulltext 
  8  FROM   gv$session g, 
  9         v$sql s 
 10  WHERE  g.wait_class = ‘Application‘ 
 11         AND g.sql_hash_value = s.hash_value;  
 
   INST_ID        SID    SERIAL# EVENT                         USERNAME   SQL_HASH_VALUE SQL_FULLTEXT
---------- ---------- ---------- ----------------------------- ---------- --------------  ----------------------
         1         14      13392 enq: TX - row lock contention  TEST        874051616    insert into test values(1000,‘jimmy‘)
 
SQL> col type for a12;
SQL> select /*+rule*/
  2         inst_id,
  3         decode(request, 0, ‘holder‘, ‘waiter‘) role,
  4         sid,
  5         type,
  6         request,
  7         lmode,
  8         block,
  9         ctime,
 10         id1,
 11         id2
 12  from gv$lock
 13  where (id1, id2, type) in
 14                  (select id1, id2, type from gv$lock where request >0)
 15  order by ctime desc ,role; 
 
   INST_ID ROLE                SID TYPE            REQUEST      LMODE      BLOCK      CTIME        ID1        ID2
---------- ------------ ---------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
         1 holder                8 TX                    0          6          1         92     589835       2213
         1 waiter               14 TX                    4          0          0         70     589835       2213

 

会话1(会话ID为8)提交事务后

 

SQL> insert into test values(1000, ‘kerry‘);
 
1 row created.
 
SQL> commit;

 

会话2(会话ID为14)遇到ORA-00001错误提示

SQL> insert into test values(1000,‘jimmy‘);
insert into test values(1000,‘jimmy‘)
*
ERROR at line 1:
ORA-00001: unique constraint (TEST.PK_TEST) violated

这个在ORACLE 10g以及以上版本都无法测试(Oracle 9i可以测试),因为ORACLE 10g中,对于单个数据块,Oracle缺省最大支持255个并发,MAXTRANS参数在ORACLE 10g以及以上版本被废弃了,即使你使用下面SQL指定了maxtrans为1, 但是你查看表的定义,你会发现maxtrans依然为255。

SQL> drop table test purge;
 
Table dropped.
 
 
SQL> create table test 
  2  (
  3     id  number(10), 
  4     name varchar(16)
  5  )  initrans 1 maxtrans 1;
 
Table created.

所以这个场景只会发生在ORACLE 9i的版本中或是并发非常高的系统当中。

 

Waits due to rows being covered by the same BITMAP index fragment

这个源于位图索引的特性,更新位图索引的一个键值,会指向多行记录,所以更新一行就会把该键值指向的所有行锁定

SQL> create table employee 
  2  (
  3  employee_id  number(10),
  4  employee_name nvarchar2(24),
  5  sex    varchar2(6) 
  6  );
 
Table created.
 
SQL> create bitmap index idx_employee_bitmap on employee(sex);
 
Index created.
 
SQL> insert into employee
  2  select 1000, ‘kerry‘, ‘female‘ from dual union all
  3  select 1001, ‘jimmy‘, ‘female‘ from dual;
 
2 rows created.
 
SQL> commit;
 
Commit complete.
 
SQL> 
 
 
会话1:
 
SQL> update employee set sex=‘male‘ where employee_id=1000;
 
1 row updated.
 
 
会话2:
 
SQL> update employee set sex=‘male‘ where employee_id=1001;
 
 
 
会话3:
SQL> col type for a32;
SQL> SELECT sid,      
  2         type,     
  3         id1,      
  4         id2,      
  5         lmode,    
  6         request   
  7  FROM   v$lock    
  8  WHERE  type = ‘TX‘
 
       SID TYPE                                    ID1        ID2      LMODE    REQUEST
---------- -------------------------------- ---------- ---------- ---------- ----------
        14 TX                                   589836       2211          0          4
        14 TX                                   131096       2204          6          0
         8 TX                                   589836       2211          6          0
 
SQL> col event for a40 
SQL> col username for a10 
SQL> col sql_fulltext for a80 
SQL> SELECT g.inst_id, 
  2         g.sid, 
  3         g.serial#, 
  4         g.event, 
  5         g.username, 
  6         g.sql_hash_value, 
  7         s.sql_fulltext 
  8  FROM   gv$session g, 
  9         v$sql s 
 10  WHERE  g.wait_class = ‘Application‘ 
 11         AND g.sql_hash_value = s.hash_value;  
 
   INST_ID        SID    SERIAL# EVENT                          USERNAME   SQL_HASH_VALUE SQL_FULLTEXT
---------- ---------- ---------- ------------------------------ ---------- -------------- ---------------------------------
         1         14      13392 enq: TX - row lock contention   EST           2418349426 update employee set sex=‘male‘ where employee_id=1001
 
SQL> col type for a12;
SQL> select /*+rule*/
  2         inst_id,
  3         decode(request, 0, ‘holder‘, ‘waiter‘) role,
  4         sid,
  5         type,
  6         request,
  7         lmode,
  8         block,
  9         ctime,
 10         id1,
 11         id2
 12  from gv$lock
 13  where (id1, id2, type) in
 14                  (select id1, id2, type from gv$lock where request >0)
 15  order by ctime desc ,role;    
 
   INST_ID ROLE                SID TYPE            REQUEST      LMODE      BLOCK      CTIME        ID1        ID2
---------- ------------ ---------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
         1 holder                8 TX                    0          6          1        116     589836       2211
         1 waiter               14 TX                    4          0          0         76     589836       2211
 
SQL> 

 

其它场景

There are other wait scenarios which can result in a SHARE mode wait for a TX lock but these are rare compared to the examples given above.

Example:

If a session wants to read a row locked by a transaction in a PREPARED state then it will wait on the relevant TX lock in SHARE mode (REQUEST=4). As a PREPARED transaction should COMMIT , ROLLBACK or go to an in-doubt state very soon after the prepare this is not generally noticeable.

例如,表存在主外键读情况,主表不提交,子表那么必须进行等待.

初始化测试表

SQL> create table employee( employee_id  number, employee_name varchar(12), depart_id number);
 
Table created.
 
SQL> create table department(depart_id  number primary key, depart_name varchar2(24));
 
Table created.

 

会话1:

 
SQL> select sid from v$mystat where rownum=1;
 
       SID
----------
        75
 
SQL> insert into department values(1000, ‘sales‘);
 
1 row created.

 

会话2:

SQL> select sid from v$mystat where rownum=1;
 
       SID
----------
       200
 
SQL> insert into employee values(1024, ‘kerry‘, 1000); --一直挂起,直到会话1提交

 

 

会话3

SQL> show user;
USER is "SYS"
SQL> select sid from v$mystat where rownum=1;
 
       SID
----------
        73
 
SQL> col type for a12;
SQL> select /*+rule*/
  2         inst_id,
  3         decode(request, 0, ‘holder‘, ‘waiter‘) role,
  4         sid,
  5         type,
  6         request,
  7         lmode,
  8         block,
  9         ctime,
 10         id1,
 11         id2
 12  from gv$lock            
 13  where (id1, id2, type) in            
 14                  (select id1, id2, type from gv$lock where request >0)
 15  order by ctime desc ,role
 
   INST_ID ROLE          SID TYPE            REQUEST      LMODE      BLOCK      CTIME        ID1        ID2
---------- ------ ---------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
         1 holder         75 TX                    0          6          1        197     458758       2371
         1 waiter        200 TX                    4          0          0         97     458758       2371
 
 
SQL> COL TX FOR A24;
SQL> SELECT 
  2     sid, seq#, state, seconds_in_wait,
  3     ‘TX-‘||lpad(ltrim(p2raw,‘0‘),8,‘0‘)||‘-‘||lpad(ltrim(p3raw,‘0‘),8,‘0‘) TX,
  4     trunc(p2/65536)      XIDUSN,
  5     trunc(mod(p2,65536)) XIDSLOT,
  6     p3                   XIDSQN
  7    FROM v$session_wait 
  8   WHERE event=‘enq: TX - row lock contention‘;
 
       SID       SEQ# STATE               SECONDS_IN_WAIT TX                           XIDUSN    XIDSLOT     XIDSQN
---------- ---------- ------------------- --------------- ------------------------ ---------- ---------- ----------
       200        108 WAITING                         145 TX-00070006-00000943              7          6       2371
 
SQL> 

 

 

另外遇到enq: TX - row lock contention等待事件,单实例与RAC是否有所区别呢,如果是RAC,需要注意识别实例,否则很容易误杀其它会话?如果你查到了blocker,是不是应该直接kill掉呢? 这个必须要先征询客户的意见,确认之后才可以杀掉。不能因为外在压力和自己的急躁而擅自Kill会话。

在WAITEVENT: "enq: TX - row lock contention" Reference Note (文档 ID 1966048.1)中,也有一些比较有意思的SQL,可以参考一下

SQL> SELECT row_wait_obj#, row_wait_file#, row_wait_block#, row_wait_row#
  2    FROM v$session
  3   WHERE event=‘enq: TX - row lock contention‘
  4     AND state=‘WAITING‘;
 
ROW_WAIT_OBJ# ROW_WAIT_FILE# ROW_WAIT_BLOCK# ROW_WAIT_ROW#
------------- -------------- --------------- -------------
        75389              4             211             0
 
 
SQL> set linesize 240;
SQL> select owner, object_name from dba_objects
  2  where object_id=75389;  
 
OWNER                          OBJECT_NAME
------------------------------ ------------------
TEST                           TEST
 
 
SQL> SELECT 
  2     sid, seq#, state, seconds_in_wait,
  3     ‘TX-‘||lpad(ltrim(p2raw,‘0‘),8,‘0‘)||‘-‘||lpad(ltrim(p3raw,‘0‘),8,‘0‘) TX,
  4     trunc(p2/65536)      XIDUSN,
  5     trunc(mod(p2,65536)) XIDSLOT,
  6     p3                   XIDSQN
  7    FROM v$session_wait 
  8   WHERE event=‘enq: TX - row lock contention‘
  9  ;
 
       SID       SEQ#            SECONDS_IN_WAIT        TX                    XIDUSN    XIDSLOT     XIDSQN
---------- ---------- --------- --------------- --------------------------- ---------- ---------- ----------
       137         27 WAITING                     245 TX-00040012-000007E6        4         18       2022

在TX - row lock contention 的一些场景 这篇文章里面介绍了出现enq: TX - row lock contention等待的案例场景,网络问题、执行计划问题、应用问题等。在我遇到的实际案例当中,网络问题造成的‘enq: TX - row lock contention‘较多,因为现在大多数是无线网络,有些应用程序出现问题或网络出现问题过后,导致数据库中的进程依然在,但是对于的UPDATE等DML操作没有及时提交。从而出现较严重的enq: TX - row lock contention

 

诊断定位enq: TX - row lock contention等待事件

在官方文档 ID 62354.1里面,提供了一个根据AWR 快照ID查找那些段出现row lock 等待较多的SQL,这个也有一定的参考意义。

SELECT P.snap_id,
  P.begin_interval_time,
  O.owner,
  O.object_name,
  O.subobject_name,
  O.object_type,
  S.row_lock_waits_delta
FROM dba_hist_seg_stat S,
  dba_hist_seg_stat_o                    

人气教程排行