淺談DML阻塞(下)

realkid4發表於2012-02-11

 

上面我們提到了關於普通DML操作(insert,update和delete)連帶的一些blocking情況。本篇中,我們繼續介紹兩種連帶由於DML操作引起的blocking情況。

 

ü        各種約束引起的block鎖定

 

上面談到的主鍵鎖定block,本質上就是一種約束引起的資料庫邏輯blocking。按照這個思路,我們可以猜出具有相同屬性的唯一索引(Unique Index)也具有DML操作blocking的問題。

 

 

SQL> alter table t drop constraint PK_T;

Table altered

 

--唯一索引建立

SQL> create unique index u_idx_t on t(id);

Index created

 

SQL> select * from t;

        ID NA

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

         1 dfs

         2 df

 

 

兩個會話修改資料表的唯一索引列id。

 

--第一會話

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

       SID

----------

       156

 

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

1 row updated

 

 

第二會話涉及到相關記錄。

 

 

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

       SID

----------

       144

 

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

(資料被blocking

 

 

此時,鎖情況如下:

 

 

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

 

       SID TYPE        ID1        ID2      LMODE    REQUEST      BLOCK

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

       144 TX        65554       1246          0          4          0

       144 TM        54736          0          3          0          0

       144 TX       327712       1268          6          0          0

       156 TX        65554       1246          6          0          1

156 TM        54736          0          3          0          0

 

 

從鎖的情況來看,基本和主鍵鎖定阻塞的情況相似。

 

作為Unique Index,我們需要注意一點不同之處,就是關於空值null。與主鍵約束不同,唯一索引列的取值中,是允許存在空值的。唯一索引列中,可能存在多個空值的情況。如果我們要將列值修改為null,那麼鎖定的機率就會小很多。

 

 

--會話一

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

1 row updated

 

--會話二

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

1 row updated

 

 

在唯一索引中,null是一種特殊值,是允許重複的。

 

ü        ITL事務槽引起的DML操作鎖定

 

我們檢查資料字典檢視,對資料表T存在兩個屬性。

 

 

SQL> select INI_TRANS,  MAX_TRANS from dba_tables where table_name='T' and wner='SYS';

 

 INI_TRANS  MAX_TRANS

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

1        255

 

 

在資料表完全定義DDL語句中,也存在相應的片段。

 

 

    "NA" VARCHAR2(10)

   ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING

  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645

 

 

這裡我們只簡單談一下maxtrans這個古老的引數體系。我們知道,Oracle資料按照邏輯結構是儲存在“表、段、分割槽和資料塊”若干層次結構中的。作為最底層結構的資料塊,分為block header和data rows部分。其中,block header中包括了關於資料塊的空間分配資訊以及事務管理資訊。其中的事務資訊就是ITL(Interested Transaction List),負責記錄該資料塊正在進行的事務資訊。

 

ITL是有大小的限制的,早期Oracle空間管理中,ITL扮演者很重要的角色。定義資料表的時候,指定的initrans就是每個資料塊中最初設定的ITL事務個數。當該資料塊發生事務的時候,在ITL上會寫入該事務的資訊,佔據一個ITL位置。當該資料塊進行的事務超過initrans設定的時候,資料塊就會自動進行擴充動作。擴充的最大個數,就是MaxTrans,預設值為255。

 

設想一種場景,如果我們將資料塊的maxtrans設定為很小(Oracle 9i中最小為2),那麼同時超過2個會話對同一個資料塊的行進行DML操作,就會發生ITL爭用阻塞現象。第三個事務就會阻塞。

 

在一些早期出版的Oracle著作中,常用該型別block的演示內容(如Tom的幾本名著)。但是注意,這個屬性隨著Oracle 10g的到來已經被廢止,不能顯示的設定該引數。該引數也失去了設定的機會。

 

透過命令列語句,可以修改maxtrans屬性。

 

 

SQL> alter table t maxtrans 1;

Table altered

 

SQL> select INI_TRANS,  MAX_TRANS from dba_tables where table_name='T' and wner='SYS';

 

 INI_TRANS  MAX_TRANS

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

         1        255

 

 

修改語句並沒有變化。

 

但是注意,這並不意味著ITL最大事務槽機制的失效。在資料中,我們找到了下面一段內容:

 

 

Oracle Database now automatically allows up to 255 concurrent update transactions for any data block, depending on the available space in the block.

The database ignores MAXTRANS when specified by users only for new objects created when the COMPATIBLE initialization parameter is set to 10.0 or greater.

 

 

Oracle自動會將255作為事務的最大個數上限,而不是使用者的設定。

 

筆者由於只有Oracle 10g以上版本資料庫,9i的設定實驗無法進行,表示遺憾。

 

3、結論

 

Oracle是一個支援高併發的資料庫DBMS系統。藉助行鎖機制,Oracle嚮應用提供了較大限度的併發可能性。但是,這種併發並不是絕對的,很多場景都會讓多行之間的DML操作相互影響。

 

本文我們討論了該種機制,以及原因。此外,如外來鍵列需要加索引等等問題,在筆者之前的文章中,已經加以探討過了。

 

 

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

相關文章