DML操作引起的blocking(二)

realkid4發表於2011-02-20

 

2、並行插入相同主鍵記錄

 

我們嘗試構建一個同時插入主鍵相同的記錄,看看Oracle是如何處理這樣的情況。這兩條資料就是相關資料,因為正常條件下,兩條資料是無法並存的。

 

 

//session1(sid=158)中

 

SQL> insert into t values (1,'ddd');

 

已建立 1 行。

 

//session2(sid=141)中

 

SQL> insert into t values (1,'ddddfsf');

session2被阻塞)

 

 

發生了阻塞!session2因為插入了id=1的資料,但是之前已經存在id=1的記錄,即使這條記錄還沒有被commit。

 

//檢視現象

SQL> select * from v$locked_object;

 

    XIDUSN    XIDSLOT     XIDSQN  OBJECT_ID SESSION_ID ORACLE_USERNAME                OS_USER_NAME                   PROCESS      LOCKED_MODE

---------- ---------- ---------- ---------- ---------- ------------------------------ ------------------------------ ------------ -----------

         8         19        891      53606        141 SCOTT IBM-VS2A1BHCNS0\ibm  772:3932  3

         6         17        840      53606        158 SCOTT      IBM-VS2A1BHCNS0\ibm 636:1036               3

 

SQL> select * from v$lock where sid in (141,158);

 

ADDR     KADDR           SID TYPE        ID1        ID2      LMODE    REQUEST      CTIME BLOCK

-------- -------- ---------- ---- -------------------

6C8344A8 6C8344BC        141 TX       393233        840          0          4         96 0

6BDC4074 6BDC408C        158 TM        53606          0          3          0        129 0

6BDC4138 6BDC4150        141 TM        53606          0          3          0         96 0

6BE185A8 6BE186C4        158 TX       393233        840          6          0        129 1

6BE29A54 6BE29B70        141 TX       524307        891          6          0         96 0

 

 

 

SQL> select sid, serial#, lockwait, sql_id, blocking_session_status,EVENT#, EVENT

  2  from v$session where sid in (141,158);

 

       SID    SERIAL# LOCKWAIT SQL_ID        BLOCKING_SESSION_STATUS     EVENT# EVENT

---------- ---------- -------- ------------- ----------------------- ---------- ----------------------------------------------------------------

       158         47                        NO HOLDER                      256 SQL*Net message from client

       141        122 6C8344BC 515n1g3av68fc VALID                          183 enq: TX - row lock contention

 

首先,我們分析一下v$locked_object檢視。兩個會話session分別在undo表空間分配了相應的空間,準備存放undo資料映象。並且給這兩個段加入了共享鎖(Lmode=3)。

 

v$lock檢視變得略有複雜。首先,我們觀察session1(sid=158)的情況。session1的情況和上面沒有多少區別。現在資料表T上加一個共享物件鎖(TM鎖,Lmode=3)。之後,在Undo區(393233/840)上分配空間,儲存資料映象,並且加入了一個排他鎖(TX Lmode=6)。當session1(sid=158)完成之後,session2(sid=141)嘗試將相同id的資料插入到資料表中。首先,先給物件T加入一個共享鎖物件(TM鎖,LMODE=3)。之後,session2嘗試給已經為session1排他(lmode=6)的undo空間(393233/840),加一個TX鎖,型別為lmode=4(共享鎖型別),要求共享undo空間(393233/840)。這樣,session1和session2在這個undo空間上存在了blocking,因為lmode4和6之間不能並存。於是,session2被blocking。

 

此外,session2為了進行insert操作,還分配了一個新的undo空間(53606          0),實行lmode=3的事務鎖。

 

從會話v$session等待情況看,會話2在等待事件“enq: TX - row lock contention”,等待session1釋放資料行鎖。

 

 

結論:當兩個會話在同時新增加一個記錄的時候,如果輸入的主鍵相同,一個會話會發生blocking。此時,Oracle是難以做決定,前一個會話如果被rollback,第二個事務不存在問題。如果前一個會話提交,第二個事務對應資料行就是非法的資料。在這種情況下,Oracle只能是blocking一個會話了。

 

 

 

3、同時修改相同一條記錄

 

當我們嘗試修改一條相同的記錄時,會發生什麼呢?

 

 

//session1(sid=158)

 

SQL> update t set name='dfs' where id=1;

 

已更新 1 行。

 

SQL>

 

//session2(sid=141)

 

SQL> update t set name='fs' where id=1;

(阻塞)

 

 

出現了阻塞blocking。我們觀察一下鎖的情況。

 

 

SQL> select * from v$locked_object;

 

    XIDUSN    XIDSLOT     XIDSQN  OBJECT_ID SESSION_ID PROCESS      LOCKED_MODE

---------- ---------- ---------- ---------- ---------- ------------ -----------

         0          0          0      53606        141 772:3932               3

         6         16        840      53606        158 636:1036               3

 

SQL> select * from v$lock where sid in (141,158);

 

ADDR     KADDR           SID TYPE        ID1        ID2      LMODE    REQUEST      CTIME  BLOCK

-------- -------- ---------- ---- -------------------

6C8344A8 6C8344BC        141 TX       393232        840          0          6         42 0

6BDC4074 6BDC408C        158 TM        53606          0          3          0         87 0

6BDC4138 6BDC4150        141 TM        53606          0          3          0         42 0

6BE185A8 6BE186C4        158 TX       393232        840          6          0         87 1

 

 

SQL> select sid, serial#, lockwait, sql_id, blocking_session_status,EVENT#, EVENT

  2  from v$session where sid in (141,158);

 

       SID    SERIAL# LOCKWAIT SQL_ID        BLOCKING_SESSION_STATUS     EVENT# EVENT

---------- ------ -------------------------------------

   141         47 6C8344BC fgjfccu4as8xv VALID       83 enq: TX - row lock contention

158        122                      NO HOLDER  256 SQL*Net message from client

 

 

從檢視情況下,雖然在修改相同資料行的時候,都是後一個session2被阻塞住。但是,在加鎖方式上存在一些差異。這點從v$lock檢視上可以分析出。

 

先看v$locked_object,session2(sid=141)的undo空間鎖是沒有建立的,前三個資料列為0。

 

v$lock檢視中,session2發起了兩個鎖,一個是對資料表的共享鎖TM。另一個鎖是對session1所開啟的undo段進行行排他(Lmode=6)要求。因為其上已經存在session1的排他,兩者不能並存。於是,session2被阻塞住。

 

 

結論:當兩個會話在同時修改一個資料時。對共享資源的佔用就是第一個會話undo段空間物件。後一個session會被blocking。

 

 

4、刪除相同的資料

 

最後我們看看刪除資料時候的情況。

 

//session1(sid=149)

SQL> conn scott/tiger@orcl;

已連線。

 

SQL> delete t where id=1;

 

已刪除 1 行。

 

SQL> select sid from v$mystat where rownum<2;

 

       SID

----------

       149

 

//session2(Sid=156)

SQL> conn scott/tiger@orcl

已連線。

SQL> select sid from v$mystat where rownum<2;

 

       SID

----------

       156

 

SQL> delete t where id=1;

 

 

刪除相同的資料時,被blocking。

 

 

 

SQL> select * from v$locked_object;

 

    XIDUSN    XIDSLOT     XIDSQN  OBJECT_ID SESSION_ID ORACLE_USERNAME  OS_USER_NAME  PROCESS   LOCKED_MODE

---------- ---------- ---------- ---------- --------- -----------

   8         22        896      53606        149 SCOTT  IBM-VS2A1BHCNS0\ibm   3752:588 3

   0         0         0        53606    156 SCOTT IBM-VS2A1BHCNS0\ibm  1428:3376   3

 

 

SQL> select * from v$lock where sid in (149,156);

 

ADDR     KADDR           SID TYPE        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK

-------- -------- ---------- ----  ----------

6C8344A8 6C8344BC        156 TX       524310        896          0          6        130 0

6BDC4074 6BDC408C        149 TM        53606          0          3          0        309 0

6BDC4138 6BDC4150        156 TM        53606          0          3          0        130 0

6BE23C64 6BE23D80        149 TX       524310        896          6          0        309 1

 

 

SQL> select sid, serial#, lockwait, sql_id, blocking_session_status,EVENT#, EVENT

  2  from v$session where sid in (149,156);

 

       SID    SERIAL# LOCKWAIT SQL_ID        BLOCKING_SESSION_STATUS     EVENT# EVENT

---------- ---------- -------- ------------- ----------------------- ---------- ----------------------------------------------------------------

149        381                        NO HOLDER      256 SQL*Net message from client

156           493 6C8344BC g2pvqwhq0pwjc VALID          183 enq: TX - row lock contention

 

 

刪除的特徵和修改相同,都是兩個會話爭用這個資料行對應的鎖,之後發生鎖互斥現象,引發blocking。

 

 

結論:在刪除兩條相同資料行的情況下,是可能發生blocking的。

 

 

綜合上面的研究,我們可以發現。Oracle採用的多版本一致度和事務行鎖機制,最大限度的保證了並行特性發揮。但是,存在並行、存在資源獨佔使用,就存在鎖機制,有鎖機制就意味著總會有訪問被序列化。但是,不得不承認,Oracle在鎖機制上,已經做到了相當小的範圍。

 

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-687571/,如需轉載,請註明出處,否則將追究法律責任。

相關文章