佇列、資源與鎖

lhrbest發表於2016-09-06


一、佇列與共享資源

     共享資源可以被多個會話、程式同時訪問,因此它的訪問需要保護。Oracle中,除了PGA,所有的東西(包括記憶體、磁碟、CPU、表、索引、事務等等,種類太多,一概用東西兩字來代表)都是共享資源。多個程式或會話對共享資源操作時,就需要排隊。這裡所需要排的隊就是佇列(Enqueue)。訪問不同的共享資源,需要排不同的隊。可以這樣說,有多少種佇列,就有多少種需要保護的共享資源。佇列的名字一般是兩個位元組構成,如TMTXJQ,……。具體所有佇列的種類、名字,參見V$LOCK檢視介紹中的附表。


二、佇列標識

     我們以TM為例,它是DML佇列鎖。在對錶作DML操作時,需要先在此排隊,正式點的說法是:需要先獲得TM佇列鎖。TM也被稱作表鎖,因為它主要是在對錶作操作是獲得的。如果資料庫中有1000個表,針對這一千個表,並非只有一個佇列,要是這樣的話也不太合理。1000個表,就應該有1000TM佇列,這樣才附合常理。如果一千個佇列都叫TM,將來操作時不好區分,因此,需要為這一千個TM佇列分別名命,這個名字,也被稱為佇列標識。TM佇列的命名格式為:TM-OID-0。其中OIDObject ID,即物件ID。最後一部分一般都是0。假如AA表的OID6636,它的佇列標識就是TM-6636-0

     每種佇列的命名格式各不相同,總的來說是“佇列名-ID1-ID2”,ID1ID2分別是兩個引數,對於TM佇列來說,ID1OIDID20


三、資源結構

     繼續我們上面的假設,如資料庫中有一千個表,這就要對應一千個TM佇列。但只有當操作到哪個表了,才會為它建立相關的佇列資訊。比如會話釋出了對AA表的更新操作,需要在SGA中為AA建立相關的TM佇列資訊。這些相關AATM資訊,也被稱為“資源結構”(KSQRSKSQ是核心服務佇列的簡寫,RSResource Structure的簡寫,即資源結構)。每一個資源結構維持一個所有者、等待者和轉換者的列表。如下圖:

佇列、資源與鎖

資源結構前的即是佇列標識,也可以作為資源結構標識(資源標識)。

每一個所有者、等待者和轉換者有一個鎖結構(Ksqlk),簡單點說每一個所有者、等待者和轉換者有一個連結串列,此連結串列由會話、鎖模式等資訊構成,具體描述了什麼會話以什麼模式獲得此資源結構。具體如下:

     1)如果會話獲得鎖,鎖結構將在所有者列表上

     2)如果會話正在等待獲得鎖,鎖結構將在等待者列表上

     3)如果鎖已被獲得,但會話正在等待它被轉換到一種不同的模式,鎖結構將在轉換者列表上

     所有資源結構組成一個資源表,資源表和資源結構上的鎖都被分配在SGA中。資源表中總的行數由初始化引數ENQUEUE_RESOURCES決定,且資源表中的行可以在X$KSQRS中被看到。正在被使用的將在V$RESOURCE中顯示。還可以在v$resource_limit中看到資源結構數量的限制和使用情況:

sid=9 pid=10> select * from v$resource_limit where resource_name = 'enqueue_resources';

RESOURCE_NAME CURRENT_UTILIZATION MAX_UTILIZATION INITIAL_ALLOCATION   LIMIT_VALUE

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

enqueue_resources          32              32        968            UNLIMITED

     可以看到,當前使用了32個資源結構,最多時使用了32個資源結構,初始化引數中分配了968個資源結構。最多使用是UNLIMITED,沒有限制。由於Oracle 9i採用的演算法,我們在X$KSQRS中看到的總行數並不是968,而是992。為確保重用,資源表中未用的資源結構被放置在一個連線列表,稱為:Resource Free List。我們可以釋出一些更新宣告,不要提交,這樣佔用的TMTX資源結構一直不會釋放。觀察X$KSQRSTM資源結構的佔用增多,但檢視的總行數不變,還是992。新增的TMTX資源結構佔用了其他已經釋放的資源結構。


四、資源結構雜湊表

     為了在資源表中快速找到某一資源結構,Oracle當然還是要使用HASH演算法。Oracle根據資源標識計算HASH值。當然,和Library cache一樣,資源表中已被佔用的資源結構的HASH值構成了一個個HASH Buckut

佇列、資源與鎖

  上圖就是HASH Bucket和資源結構的圖,可以看到和Library cache中的很像。HASH演算法嗎,所有的HASH演算法都會有很多共同點。從上圖中可以看到,想訪問Hash Bucket,需要Enqueue hash chain閂,它需要保護上圖中的HASH表,和每個Hash Bucket後的Hash鏈。它的數量由隱含引數_enqueue_hash_chain_latches控制。Enqueue hash chain閂類似於Buffer cache chain閂。它們都是一個閂要管理多個雜湊桶,不過Enqueue hash chain更特殊,在單CPU環境中,只有一個,卻要管理所有的雜湊桶,這是因為佇列的爭用,畢競比Buffer要小的多。

  Oracle中所有關於HASH的演算法,都要有HASH表、HASH鏈和保護HASH鏈的閂,HASH表不需要保護,這是因為HASH表是大小固定的陣列。每一個陣列元素就是一個Hash Bucket。每個雜湊桶的雜湊值也都是事先定好的。因此不存在對雜湊桶的更改,如插入一個雜湊桶、修改一個雜湊桶的雜湊值或刪除一個未使用的雜湊桶等等,這些操作都是不存在的。因此,既然不會有修改操作,雜湊表就不需保護。需要保護的是每個雜湊桶後的鏈。每個桶後的鏈中,都可以掛多個物件,我們可能向鏈上新增或刪除物件,既然有修改,就需要保護。

  佇列資源Hash表的長度由_enqueue_hash控制,其始值來源於SESSION引數,初始是375。我們的資源表共有992行,而雜湊桶只有375個,這必然會有多個資源結構排在某一個雜湊桶後面。如果曾經增加過ENQUEUE_RESOURCES的值,也就是說,資源結構比系統預設的還要更多一些,但控制雜湊表長度的_enqueue_hash引數值如果不跟著增加。這就意味著每個雜湊桶下要掛接更多的資源結構,這有可能因起Enqueue hash chain閂的競爭。如何觀察閂的使用情況這是下一章節的內容,這裡就不多說了。_enqueue_hash的初始值是根據Sessions引數來定的,計算公式如下:((sessions-10)*2)+55,預設 ((170-10)*2)+55,正好等於375,它並不隨ENQUEUE_RESOURCES的增加而增加。

佇列、資源與鎖


  佇列、資源結構和鎖結構的關係如上圖。上圖是分別在兩個會話中釋出如下宣告後的結果:

  在會話10sid=10 pid=11> insert into a1 values(1,1,1);

已建立 行。

  在會話12sid=12 pid=12> insert into a1 values(2,2,2);

已建立 行。

  檢視雜湊表檢視:

sid=9 pid=10> select * from v$resource where type ='TM';

ADDR     TY        ID1        ID2

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

7B6D5C40 TM       6657          0

可以看到,有一個TM佇列,地址是7B6D5C40,物件ID6657,這個正是A1表。

檢視V$LOCK檢視:

sid=13 pid=13> select * from v$lock where sid>=8;

ADDR  KADDR     SID   TY        ID1     ID2  LMODE    REQUEST      CTIME      BLOCK

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

7AF661FC 7AF66308        10 TX     458765       2212          6          0        452          0

7AF3A074 7AF3A088       10 TM       6657          0          3          0        452          0

7AF837AC 7AF838B8       12 TX     327686       2355          6          0         84          0

7AF3A17C 7AF3A190      12 TM       6657          0          3          0         84          0

  上面的結果中顯示,TM-6657-0有兩個鎖,地址分別是7AF3A0887AF3A190

  說明,上圖中的資訊,部分來自於佇列結構的DUMP,宣告如下,有興趣可以自己試試。

  sid=10 pid=11> alter session set events 'immediate trace name enqueues level 4';

  雜湊表的長度,由_enqueue_hash設定,資源結構的數量(也稱資源表的長度),由ENQUEUE_RESOURCES設定。鎖結構的的數量,也可以由DBA控制,隱含引數_enqueue_locks就是設定鎖結構數量的(也稱佇列鎖:Enqueue Lock),預設值2230。可以被看到在X$KSQEQ中,正在被使用的在V$ENQUEUE_LOCK顯示。但是,有關TMTX這兩個佇列的鎖和其他情況的佇列鎖不一樣,除非它們發生了Enqueue等待,否則它們並不在X$KSQEQ結構中顯示,因此在X$KSQEQ之上的V$ENQUEUE_LOCK也沒有正在使用中的TXTM佇列鎖的情況。Oracle使用不同的結構來管理TXTM排除。TXX$KTCXB,核心事務控制事務物件,V$TRANSACTION_ENQUEUE的基礎檢視。它的尺寸由transactions初始化引數控制。有關TX的我們下面專門再說。再看TMX$KTADM,核心事務訪問定義DML鎖。X$KTADM的尺寸由DML_LOCKS定義,也就是TM鎖的數量。X$KTADMDBA意義不大,可以為我們提供鎖的模式、加鎖的時間、正在請求的模式、會話SID等資訊,資訊量並不比V$LOCK中多。透過上兩個X$檢視觀察正在使用中的TMTX鎖的最好辦法是:

set linesize 800

col KTCXBNAM for a20

select * from x$ktcxb where ktcxblkp in (select kaddr from v$lock where type='TX');

select * from x$ktadm where ksqlkadr in ( select kaddr from v$lock where type='TM');

我們也可以在V$RESOURCE_LIMIT中看到有關佇列鎖的使用情況:

sid=9 pid=10> select * from v$resource_limit where resource_name like 'enqueue%';

RESOURCE_NAME CURRENT_UTILIZATION MAX_UTILIZATION INITIAL_ALLOCATION   LIMIT_VALUE

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

enqueue_locks                26              30       2230                 2230

enqueue_resources             26              26       1200            UNLIMITED

注意enqueue_lockstransactionsDML_LOCKS的關係,enqueue_locks是總的佇列鎖的數量,transactions定義了在總的佇列鎖中,TX鎖的數量,DML_LOCKS是總佇列鎖中TM鎖的數量。也就是說transactionsDML_LOCKSenqueue_locks的一部分。


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

相關文章