[20151208]关于Oracle Row Lock.txt

[20151208]关于Oracle Row Lock.txt

--参考链接
https://blogs.oracle.com/askmaclean/entry/know_more_about_oracle_row

大家都知道如何2个用户修改相同的记录,会出现enq: TX – row lock contention,另外一个用户会等待前面的用户修改的提交或者回
滚,如果不提交,该用户会一直等待,除非前面的用户给kill或者执行commit,rollback操作。而我们都知道在Oracle中实现了细粒度的
行锁row lock,且在ORACLE的内部实现中没有使用基于内存的行锁管理器,row lock是依赖于数据块本身实现的。换句话说判定一行数据
究竟有没有没锁住,要求Server Process去pin住相应的block buffer并检查才能够发现。

--做这个测试仅仅是重复链接https://blogs.oracle.com/askmaclean/entry/know_more_about_oracle_row操作,自己加深理解。

1.环境:
SCOTT@book> @ &r/ver1

PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

SCOTT@book> create table t_lock(id1 number,id2 number);
Table created.

SCOTT@book> insert into t_lock values (1,1);
1 row created.

SCOTT@book> commit ;
Commit complete.

--分析略。
SCOTT@book> select rowid,id1,id2 from t_lock ;

ROWID                     ID1        ID2
------------------ ---------- ----------
AAAWDnAAEAAAIU0AAA          1          1

SCOTT@book> @ &r/rowid AAAWDnAAEAAAIU0AAA
    OBJECT       FILE      BLOCK        ROW DBA                  TEXT
---------- ---------- ---------- ---------- -------------------- ----------------------------------------
     90343          4      34100          0 4,34100              alter system dump datafile 4 block 34100

2.在做测试前,先说明一下savepoint:

--oracle 在执行一系列事务时,可以使用savepoint建立一个保存点,还可以使用rollback to 回滚到特定的保存点。
--但是这里面有1个小细节必须说明:

SCOTT@book> column XIDUSN_XIDSLOT_XIDSQN format a30
SCOTT@book> select dbms_transaction.local_transaction_id()  XIDUSN_XIDSLOT_XIDSQN from dual ;
XIDUSN_XIDSLOT_XIDSQN
------------------------------

--可以发现当前会话没有任何事务。
SCOTT@book> savepoint a;
Savepoint created.

SCOTT@book> select dbms_transaction.local_transaction_id()  XIDUSN_XIDSLOT_XIDSQN from dual ;
XIDUSN_XIDSLOT_XIDSQN
------------------------------
10.16.1805

--当我们建立一个savepoint a时,也就建立了1个事务,但是如果我们执行如下:
SCOTT@book> rollback to a;
Rollback complete.

SCOTT@book> select dbms_transaction.local_transaction_id()  XIDUSN_XIDSLOT_XIDSQN from dual ;
XIDUSN_XIDSLOT_XIDSQN
------------------------------
10.16.1805

--可以发现如果我们回滚到a点,但是事务依旧存在。这个有点ddl语句在执行前会隐式发1个commit一样,也就是讲在执行savepoint a;
--会第一个先建立一个事务的开始(当然事务这是不存在,如果存在不会),再建立保存点,而rollback to a仅仅回滚到保存点,并没有
--回滚这个事务,仅仅commit或者rollback才能关闭这个事务。

SCOTT@book> rollback;
Rollback complete.

SCOTT@book> select dbms_transaction.local_transaction_id()  XIDUSN_XIDSLOT_XIDSQN from dual ;
XIDUSN_XIDSLOT_XIDSQN
------------------------------

3.测试:
--session 1:

SCOTT@book> @ &r/spid
       SID    SERIAL# SPID       PID C50
---------- ---------- ------ ------- --------------------------------------------------
        80        673 9118        31 alter system kill session '80,673' immediate;

SCOTT@book> column XIDUSN_XIDSLOT_XIDSQN format a30
SCOTT@book> select dbms_transaction.local_transaction_id()  XIDUSN_XIDSLOT_XIDSQN from dual ;
XIDUSN_XIDSLOT_XIDSQN
------------------------------

SCOTT@book> savepoint a;
Savepoint created.

SCOTT@book> column XIDUSN_XIDSLOT_XIDSQN format a30
SCOTT@book> select dbms_transaction.local_transaction_id()  XIDUSN_XIDSLOT_XIDSQN from dual ;
XIDUSN_XIDSLOT_XIDSQN
------------------------------
10.4.1809

SCOTT@book> update t_lock set id2=id2+2 where id1=1;
1 row updated.

--session 2:
SCOTT@book> @ &r/spid
       SID    SERIAL# SPID       PID C50
---------- ---------- ------ ------- --------------------------------------------------
        90        653 9124        32 alter system kill session '90,653' immediate;

SCOTT@book>update t_lock set id2=id2+3 where id1=1;

--挂起!因为修改是同一条记录.

--session 3:
SCOTT@book> @ &r/viewlock
   SID    SERIAL# USERNAME   OSUSER     MACHINE    MODULE       LOCK_TYPE    MODE_HELD  MODE_REQUE LOCK_ID1   LOCK_ID2   OWNER  OBJECT_TYP OBJECT_NAME BLOCK LOCKWAIT
------ ---------- ---------- ---------- ---------- ------------ ------------ ---------- ---------- ---------- ---------- ------ ---------- ----------- ----- --------------------
    80        673 SCOTT      oracle     gxqyydg4   SQL*Plus     DML(TM)      Row-X (SX) None       90343      0          SCOTT  TABLE      T_LOCK      No
    90        653 SCOTT      oracle     gxqyydg4   SQL*Plus     DML(TM)      Row-X (SX) None       90343      0          SCOTT  TABLE      T_LOCK      No    00000000845BF0D8
    90        653 SCOTT      oracle     gxqyydg4   SQL*Plus     Transaction  None       Exclusive  655364     1809                                     No    00000000845BF0D8
    80        673 SCOTT      oracle     gxqyydg4   SQL*Plus     Transaction  Exclusive  None       655364     1809                                     Yes

--如果这个时候回到session 1,执行:
--session 1:
SCOTT@book> rollback to a;
Rollback complete.

--查看session 2,可以发现依旧挂起。

--session 3:
SCOTT@book> @ &r/viewlock
   SID    SERIAL# USERNAME   OSUSER     MACHINE    MODULE       LOCK_TYPE    MODE_HELD  MODE_REQUE LOCK_ID1   LOCK_ID2   OWNER  OBJECT_TYP OBJECT_NAME          BLOCK LOCKWAIT
------ ---------- ---------- ---------- ---------- ------------ ------------ ---------- ---------- ---------- ---------- ------ ---------- -------------------- ----- --------------------
    90        653 SCOTT      oracle     gxqyydg4   SQL*Plus     DML(TM)      Row-X (SX) None       90343      0          SCOTT  TABLE      T_LOCK               No    00000000845BF0D8
    90        653 SCOTT      oracle     gxqyydg4   SQL*Plus     Transaction  None       Exclusive  655364     1809                                              No    00000000845BF0D8
    80        673 SCOTT      oracle     gxqyydg4   SQL*Plus     Transaction  Exclusive  None       655364     1809                                              Yes

SCOTT@book> select p1raw,p2raw,p3raw,p1,p2,p3,sid,serial#,seq#,event,state,wait_time_micro,seconds_in_wait from v$session where wait_class<>'Idle' order by event ;
P1RAW            P2RAW            P3RAW                    P1         P2         P3    SID    SERIAL#       SEQ# EVENT                                    STATE               WAIT_TIME_MICRO SECONDS_IN_WAIT
---------------- ---------------- ---------------- ---------- ---------- ---------- ------ ---------- ---------- ---------------------------------------- ------------------- --------------- ---------------
0000000062657100 0000000000000001 00               1650815232          1          0    101        181        102 SQL*Net message to client                WAITED SHORT TIME                 5               0
0000000054580006 00000000000A0004 0000000000000711 1415053318     655364       1809     90        653         29 enq: TX - row lock contention            WAITING                  2157565828            2158

--虽然这个这行已经不存在锁,对它的修改事务已经取消,但是事SID=80的事务还存在。这个时候在session 3修改该行一点记录一点问
--题都没有。

--session 3:
SCOTT@book> update t_lock set id2=id2+10 where id1=1;
1 row updated.

SCOTT@book> commit ;
Commit complete.

SCOTT@book> select * from t_lock ;
       ID1        ID2
---------- ----------
         1         11

SCOTT@book> select * From v$Lock where (sid=80 or sid=90) and type<>'AE';
ADDR             KADDR               SID TYPE         ID1        ID2      LMODE    REQUEST      CTIME   BLOCK
---------------- ---------------- ------ ----- ---------- ---------- ---------- ---------- ---------- -------
00000000845BF080 00000000845BF0D8     90 TX        655364       1809          0          6        951       0
00007FC106ADF388 00007FC106ADF3E8     90 TM         90343          0          3          0        951       0
0000000080C92AE0 0000000080C92B58     80 TX        655364       1809          6          0       1036       1

--转抄:
https://blogs.oracle.com/askmaclean/entry/know_more_about_oracle_row
那么SESSION 2 为什么无谓地等待着呢?

这就涉及到ORACLE的内部实现机制了, 注意虽然很多时候我们把 TX lock叫做 row lock , 但是实际上它们是2回事。row lock是基于
数据块实现的, 而TX lock则是通过内存中的ENQUEUE LOCK实现的。

问题在于若一个进程PROCESS K在DML过程中发现其所需要的数据行已经被其他进程锁定了,如果不依赖于内存中的TX LOCK,这意味着
PROCESS Z需要定期去读取检查该数据行锁在的数据块以发现相应的ROW LOCK是否已经被释放了,可以想象如果在OLTP环境中这样去设计
所造成的性能损失将是巨大的。

所以ROW LOCK的Release 就需要依赖于TX的ENQUEUE LOCK,大致的过程是这样的Process J 首先锁定了数据块中的一行,

Process K需要更新同样的一行数据 ,Process K读取该行锁在数据块,发现该row piece的lb不是0x0 ,而指向一个ITL,
Process Z分析该ITL就可以得到之前Process J的事务的XID,就可以找到Process J这个事务的TX lock,
PROCESS K 就会在TX resource的Enqueue Waiter Linked List上创建一个X mode(exclusive)的enqueue lock。
这样当Process J释放TX lock时,Process J就会查看该TX resource的Enqueue Waiter Linked List
并发现Process K还在那里等待,并会POST一个信息给Process K说 TX lock已经被我释放,
隐含的意思就是row lock也已经被我释放,你可以继续工作了。

--补充1点Process Z 应该是Process K。

--我的理解:(转义1下)
--当session 2需要修改相同记录时,读取该行所在数据块,发现该row piece的lb不是0x0,而指向一个ITL,通过ITL可以获得session 1
--的事务的xid,就可以找到session 1事务的TX lock。
--session 2就会在TX resource的Enqueue Waiter Linked List上创建一个X mode(exclusive)的enqueue lock。
--这样当session 1释放TX lock时,session 2就会查看该TX resource的Enqueue Waiter Linked List并发现session 2还在那里等待,
--并会POST一个信息给session 2说 TX lock已经被我释放,隐含的意思就是row lock也已经被我释放,你可以继续工作了。

--转抄:
https://blogs.oracle.com/askmaclean/entry/know_more_about_oracle_row

ROW LOCK的Release 就需要依赖于TX的ENQUEUE LOCK,大致的过程是这样的Process J 首先锁定了数据块中的一行, Process K需要更新
同样的一行数据 ,Process K读取该行锁在数据块,发现该row piece的lb不是0x0 ,而指向一个ITL,Process Z分析该ITL就可以得到
之前Process J的事务的XID,就可以找到Process J这个事务的TX lock,PROCESS K 就会在TX resource的Enqueue Waiter Linked List上
创建一个X mode(exclusive)的enqueue lock。 这样当Process J释放TX lock时,Process J就会查看该TX resource的Enqueue Waiter
Linked List 并发现Process K还在那里等待,并会POST一个信息给Process K说 TX lock已经被我释放,隐含的意思就是row lock也已经
被我释放,你可以继续工作了。

--我的理解:(转义1下)

ROW LOCK的Release 就需要依赖于TX的ENQUEUE LOCK,大致的过程是这样的Session 1首先锁定了数据块中的一行, session 2需要更新
同样的一行数据 ,session 2读取该行锁在数据块,发现该row piece的lb不是0x0 ,而指向一个ITL,session 2分析该ITL就可以得到
之前session 1的事务的XID,就可以找到session 1这个事务的TX lock,session 2就会在TX resource的Enqueue Waiter Linked List上
创建一个X mode(exclusive)的enqueue lock。 这样当session 1释放TX lock时,session 2就会查看该TX resource的Enqueue Waiter
Linked List 并发现Process K还在那里等待,并会POST一个信息给Process K说 TX lock已经被我释放,隐含的意思就是row lock也已经
被我释放,你可以继续工作了。(好像是上面的重复)

--主要的理解就是session 2如果出现阻塞,除了第1次查看数据块外,其它情况会定期的检查TX resource等待它的释放。而不是再去检
--查该数据行锁在的数据块以发现相应的ROW LOCK是否已经被释放了,可以想象如果在OLTP环境中这样去设计所造成的性能损失将是巨大
--的。

--刘工的测试还使用alter system set "_trace_events"='10000-10999:255:24';篇幅有点长,我给慢慢消化。

4.继续测试:
--session 1:
SCOTT@book> rollback ;
Rollback complete.

--session 2:
SCOTT@book> update t_lock set id2=id2+3 where id1=1;
1 row updated.

SCOTT@book> select rowid,id1,id2 from t_lock ;
ROWID                     ID1        ID2
------------------ ---------- ----------
AAAWDnAAEAAAIU0AAA          1         14

--还可以修改要重读该块现在id2=14.

SCOTT@book> rollback;
Rollback complete.

SCOTT@book> select rowid,id1,id2 from t_lock ;
ROWID                     ID1        ID2
------------------ ---------- ----------
AAAWDnAAEAAAIU0AAA          1         11

总结:
--实际上这个测试很有意思,主要理解仅仅第1次查看数据块,出现阻塞后,会定期的检查TX resource等待它的释放,而不是检查再检查数
--据块.有机会测试alter system set "_trace_events"='10000-10999:255:24';看看输出的情况。

时间: 2024-10-14 07:06:47

[20151208]关于Oracle Row Lock.txt的相关文章

Oracle中row lock contention的性能故障

这是一套Windows RAC的环境,也是之前处理  解决一则row cache lock引起的性能故障 那套环境.下面记录一下处理的经过: 1 对这一个小时进行AWR的收集和分析,首先,从报告头中看到DB Time达到近500分钟,(DB Time)/Elapsed=8,这个比值偏高: 2 再看TOP 5事件: 看到排在第一位的是enq: TX – row lock contention事件,也就是说系统中在这一个小时里产生了较为严重的行级锁等待事件. Top 5 Timed Events 通

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

enq: TX - row lock contention等待事件,这个是数据库里面一个比较常见的等待事件.enq是enqueue的缩写,它是一种保护共享资源的锁定机制,一个排队机制,先进先出(FIFO).enq: TX - row lock contention等待事件,OACLE将其归类为application级别的等待事件.有些场景是因为应用逻辑设计不合理造成的.下面我们看看enq: TX - row lock contention的英文介绍: This wait indicates ti

ORACLE 归档空间满导致的enq: TX - row lock contention

  2016年10月10日,客户一预警系统发生会话数飙高,系统响应极慢,后来确诊根源是归档空间满,引起所有redo耗尽,导致会话堆积,下面是处理过程.  操作系统:HP-UX B.11.31 U ia64  数据库版本:ORACLE 10.2.0.5 RAC  按照常规处理思路,首先查看RAC数据库的告警日志:  实例1的告警日志 Mon Oct 10 19:24:48 EAT 2016 ORACLE Instance orcl1 - Can not allocate log, archival

ORACLE AWR结合ASH诊断分析enq: TX - row lock contention

  公司用户反馈一系统在14:00~15:00(2016-08-16)这个时间段反应比较慢,于是生成了这个时间段的AWR报告,   如上所示,通过Elapsed Time和DB Time对比分析,可以看出在这段时间内服务器并不繁忙.分析Top 5 Timed Events,我们可以看到前五的等待事件     可以看到等待事件enq: TX - row lock contention占了所有等待事件17.3%的比例,猜测有可能是锁等待(enqueue等待)引起的阻塞导致,但是这个还不能下定论,因为

20161208理解enq TX - row lock contention

[20161208]理解enq TX - row lock contention.txt >SELECT * FROM v$event_name WHERE name = 'enq: TX - row lock contention'; EVENT#   EVENT_ID NAME                          PARAMETER1  PARAMETER2      PARAMETER3 WAIT_CLASS_ID WAIT_CLASS# WAIT_CLASS ------

[20121025]1条记录会有多少row pieces.txt

[20121025]1条记录会有多少row pieces.txt jonathan lewis出了一道题目Quiz,参考这个链接: http://jonathanlewis.wordpress.com/2012/03/30/quiz-night-17/ create table t1 (         col000  number(1),         col001  number(1),         col002  number(1), ...         col997  numb

【故障处理】队列等待之enq: TX - row lock contention

[故障处理]队列等待之enq: TX - row lock contention 1  BLOG文档结构图   2  前言部分 2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~: ① enq: TX - row lock contention等待事件的解决 ② 一般等待事件的解决办法 ③ 队列等待的基本知识 ④ ADDM的使用 ⑤ 如何获取历史执行计划 ⑥ 查询绑定变量的具体值 ⑦ 很多有用的查询性能的SQL语句

[20161216]关于library cache lock.txt

[20161216]关于library cache lock.txt --这几天一直在关注这个链接,http://www.itpub.net/thread-2073170-1-1.html --就是library cache lock导致挂死业务,一般引起这个问题编译包,而应用正好在使用执行这个包,以及11g口令大小写导致无法登录的问题, --我自己很久以前也遇到过一些,那时的系统是10g,http://www.itpub.net/thread-1842463-1-1.html,但是只要分析某个

[20160904]表统计信息lock.txt

[20160904]表统计信息lock.txt 晚上看链接:https://blogs.oracle.com/Database4CN/entry/%E8%AF%8A%E6%96%AD%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF%E4%B8%8D%E6%94%B6%E9%9B%86%E5%8E%9F%E5%9B%A0 提到如果导入使用ROWS=n,会导致导入的表lock,测试看看: 官方有如下解释: If ROWS=n, then statistics for all