淺談DML阻塞(上)

realkid4發表於2012-02-07

 

從資料庫系統DBMS概念提出開始,並行和序列一直是資料庫系統設計者不斷權衡的一個焦點問題。

 

1、從串並行到行級鎖

 

並行化是使DBMS支援多使用者同時訪問資料庫,提高整體效率的關鍵技術手段。不同使用者可以同時向DBMS提交執行資料庫操作語句。但是,一些場景下,對一些資源物件無控制的並行,是會引起一些問題,影響資料庫完整性等一些基本原則。在這種情況下,DBMS勢必會引入序列化機制,來保護特定的物件資源。於是Enqueue(Lock)和Latch等鎖物件就成為保護序列化訪問資源的重要手段。

 

作為當今企業級DBMS主流的Oracle,其成功很大一部分因素在於早期的系統架構設計和一些關鍵核心技術方案,如redo、行級鎖。這些在當時處在領先的理念技術,奠定了Oracle今天的市場和行業地位。

 

Oracle是一個典型的行級鎖系統。就是說,當我們進行DML操作的時候,操作會話只會將被操作記錄鎖定住。操作會話是不會阻塞其他會話對該資料表進行的DML操作的。這種機制就大大提升了會話間事務併發的效能。

 

 

SQL> select * from v$version;

 

BANNER

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

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE    10.2.0.1.0    Production

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0 Production

 

--實驗資料表

SQL> select * from t;

 

        ID NA

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

         1 Record 1

         2 Record 2

 

--在session1中

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

       SID

----------

       144

 

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

1 row updated

(此時事務並沒有提交……

 

--開啟第二個會話

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

       SID

----------

       151

 

SQL> update t set na='df' where id=2;

1 row updated

 

 

就普通的DML(insert, update, delete)操作而言,Oracle會加設兩個鎖定機制。首先是資料表級別的TM共享鎖,防止在進行事務操作的時候,出現資料物件的DDL操作,修改資料表結構。同時,對指定的資料行使用一個獨佔的TX鎖定。這樣就保證了在進行DML操作的時候,既可以保證資料完整性要求,又可以最大程度的滿足多會話併發的要求。

 

那麼,我們在進行普通DML操作的時候,有哪些情況下,兩個會話會出現阻塞情況。筆者總結常見的有如下幾種。

 

2、常見DML阻塞

 

ü        修改相同記錄引起的阻塞

 

顯而易見的情況。如果會話A在對一條記錄進行修改,事務未提交。同時會話B啟動事務要求對相同記錄進行修改。這個時候,會出現阻塞現象。

 

 

--會話A

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

 

       SID

----------

151

 

SQL> update t set na=null where id=1;

1 row updated

 

--此時會話B

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

 

       SID

----------

       149

 

SQL> update t set na='df' where id=1;

(會話Hang住)

 

 

此時,如果我們觀察兩個會話的鎖狀態,可以看出問題所在。

 

 

SQL> select sid,type,id1,id2,lmode,request,block from v$lock where sid=151 or sid=149 order by sid;

 

       SID TYPE        ID1        ID2      LMODE    REQUEST      BLOCK

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

       149 TM        54736          0          3          0          0

       149 TX       131080       1251          0          6          0

       151 TX       131080       1251          6          0          1

       151 TM        54736          0          3          0          0

 

 

兩個會話都試圖獲取到資源(131080, 1251)的獨佔權。該表示的是Undo段的地址空間位置,對應的是記錄前映象的儲存。

 

ü        主鍵列DML變化引起阻塞

 

主鍵primary key表示的是非空和唯一兩層約束保證。如果我們的DML操作涉及到主鍵列,如對主鍵列進行新增、修改和刪除,可能就會引起併發操作阻塞的情況。

 

--新增資料主鍵約束

SQL> alter table t add constraint pk_t primary key (id);

Table altered

 

SQL> select * from t;

 

        ID NA

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

         1 dfs

         2 df

 

 

如果此時,一個會話發起了修改某行主鍵列的操作。另一個會話就可能不會允許進行某些針對主鍵列的操作,即使是相同資料行。

 

--第一會話中

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

 

       SID

----------

       151

 

SQL> update t set id=3 where id=1;

1 row updated

 

--在會話二中(sid=149)

SQL> update t set id=4 where id=2;

 

1 row updated

 

SQL> rollback;

Rollback complete

 

SQL> update t set id=1 where id=2;

(阻塞)

 

 

SQL> update t set id=3 where id=2;

(阻塞)

 

從效果看,如果我們對主鍵列進行一個事務,將主鍵列取值發生可能的變化。那麼,即使這個事務沒有提交,其他會話在涉及到對該主鍵列的取值時,如果使用到了可能的變化值,會話時會被block的。

 

此時鎖定情況如下:

 

 

SQL> select sid,type,id1,id2,lmode,request,block from v$lock where sid=151 or sid=149 order by sid;

 

       SID TYPE        ID1        ID2      LMODE    REQUEST      BLOCK

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

       149 TX       458778       1293          0          4          0

       149 TM        54736          0          3          0          0

       149 TX       196650       1250          6          0          0

       151 TX       458778       1293          6          0          1

151 TM        54736          0          3          0          0

 

 

 

同一般的鎖定情況,我們發現了一些差異。第二個會話(sid=149)要求以lmode=4的方式獲取事務段鎖,被阻塞。

 

從道理上分析,Oracle這樣做也是有其“為難之處”。預設情況下,Oracle對DML操作的約束檢查是在操作進行時,而非commit時檢查。當一個主鍵列從值A變化為B的時候,Oracle接收到了另一會話事務請求,要求將一個行主鍵列變為A。Oracle如果接受了第二會話的要求,那麼第一會話rollback的時候就違反約束。如果Oracle拒絕了第二個會話的要求,那麼第一會話commit的時候就無法處理了。兩難情況下的Oracle,只能選擇block第二個會話。

 

上面的兩種情況是比較常見的,那麼我們下篇介紹其他幾種可能的block情況。

 

 

 

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

相關文章