隊列用來有序地鎖定關(guān)系與非關(guān)系型的Oracle結(jié)構(gòu)。關(guān)系型結(jié)構(gòu)可能是Oracle的數(shù)據(jù)字典表或應用程序表。例如,當Oracle更新sys.col$表或一個應用程序更新它的employee表,隊列將會被調(diào)用。如果一個服務器進程被鎖定的表所阻止,不僅僅會post一個enqueue wait等待事件,還會在v$lock,dba_lock,v$enqueue_statistics與其它視圖中顯示鎖信息。非關(guān)系型結(jié)構(gòu)被鎖定是為了阻止不合適的更改比如library cache cursor。
創(chuàng)新互聯(lián)公司主要從事成都做網(wǎng)站、成都網(wǎng)站設(shè)計、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務川匯,十載網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:18982081108
顧名思義,隊列是非常有序的,并確保以非常確定的方式更改結(jié)構(gòu)。進程的入隊列請求會被推送到適當?shù)年犃猩希斔枰幚頃r,它的入隊列條目會從隊列中彈出(也叫作dequeue)。這里并沒有什么令人興奮的地方,但是排隊不是為了冒險,而是為了確保以一種非常有序的、類似會計的方式更改Oracle結(jié)構(gòu)。
Oracle維護了數(shù)量驚人的隊列。在Oracle 10gr2中有208種隊列,在Oracle 11gr1中有247種隊列。但不必驚慌,因為你可能只會遇到幾個排隊的人。另外,如果您是一位經(jīng)驗豐富的DBA,您已經(jīng)處理過使用enqueue的行級和表級鎖。
診斷Enqueue等待
當解決隊列問題時,首先判斷隊列類型,然后確定所涉及的SQL,最后根據(jù)您對應用程序和相關(guān)Oracle內(nèi)部的知識開發(fā)解決方案。在深入研究最常見的排隊等待(事務(TX)排隊)之前,務必了解如何確定正在等待哪個排隊和oracle 10g之前和之后版本中的相關(guān)會話。
在Oracle 10g之前,所有隊列的等待事件都是enqueue。這確實很不幸,因為這要從v$lock或v$session_wait中取樣來確定隊列名稱。下面的SQL語句用來從v$session_wait中來確實enqueue名。會話4388已經(jīng)鎖表,沒有等待鎖,因此沒有顯示。隊列中的第一個會話是4387,緊接著是會話4393。判斷正在運行的SQL與所涉及的表最簡單的方式就是從v$session中查詢會話的sql_address或sql_hash_values。對于TM隊列,表可以通過p2列(ID 1列)來識別。它包含object_id,可以使用它來從dba_objects中進行查詢。這使得確定爭用對象非常簡單。
SQL> col sid format 9999 heading "Sid" SQL> col enq format a4 heading "Enq." SQL> col edes format a30 heading "Enqueue Name" SQL> col md format a10 heading "Lock Mode" trunc SQL> col p2 format 9999999 heading "ID 1" SQL> col p3 format 9999999 heading "ID 2" SQL> select sid, 2 chr(bitand(p1, -16777216) / 16777215) || 3 chr(bitand(p1, 16711680) / 65535) enq, 4 decode(chr(bitand(p1, -16777216) / 16777215) || 5 chr(bitand(p1, 16711680) / 65535), 6 'TX', 7 'Row related lock (row lock or ITL)', 8 'TM', 9 'Table related lock', 10 'TS', 11 'Tablespace and Temp Seg related lock', 12 'TT', 13 'Temporary Table', 14 'ST', 15 'Space Mgt (e.g., uet$, fet$)', 16 'UL', 17 'User Defined', 18 chr(bitand(p1, -16777216) / 16777215) || 19 chr(bitand(p1, 16711680) / 65535)) edes, 20 decode(bitand(p1, 65535), 21 1, 22 'Null', 23 2, 24 'Sub-Share', 25 3, 26 'Sub-Exlusive', 27 4, 28 'Share', 29 5, 30 'Share/Sub-Exclusive', 31 6, 32 'Exclusive', 33 'Other') md, 34 p2, 35 p3 36 from v$session_wait 37 where event = 'enqueue' 38 and state = 'WAITING' 39 / SQL> Sid Enq. Enqueue Name Lock Mode ID 1 ID 2 ----- ---- ------------------------------ ---------- -------- -------- 4387 TM Table related lock Exclusive 49911 0 4393 TM Table related lock Sub-Exlusi 49911 0 SQL> @swswp enq% Database: prod16 31-MAR-10 04:32pm Report: swswp.sql OSM by OraPub, Inc. Page 1 Session Wait Real Time w/Parameters Sess ID Wait Event P1 P2 P3 ----- ---------------------------- ------------ --------- ----- 4383 enq: TM – contention 1414332422 49911 0 4388 enq: TM – contention 1414332422 49911 0 2 rows selected. SQL> l 1 select sid, event, 2 p1, p2, p3 3 from v$session_wait 4 where event like '&input%' 5 and state = 'WAITING' 6* order by event,sid,p1,p2
與latch等待事件一樣,從Oracle 10g開始,每一種隊列都有它自己的等待事件。這節(jié)省了診斷步驟,因為我們可以通過一個簡單的查詢確定所涉及的會話和隊列類型。會話4393已經(jīng)持有表鎖并且沒有等待所以沒有顯示,會話4383和4388正等待鎖表因此post一個TM隊列等待。通過使用P2列(49911)來與dba_objects視圖的object_id關(guān)聯(lián)進行查詢來獲得被調(diào)用的表。
TX Enqueue等待
TX隊列等待是最常見的隊列等待事件。這也是最迷人的。想深入研究這個等待事件,因為它將使您更深入地了解Oracle如何管理事務并發(fā)性,這與塊克隆、undo、讀取一致性和相關(guān)事務列表有關(guān)。
TX隊列也叫作行級鎖隊列,實際上出現(xiàn)TX隊列有三個原因,并且只有一個實際上是行級鎖。每一個Oracle數(shù)據(jù)塊可以被抽象為三個區(qū)域:
.行數(shù)據(jù)包含真實的Oracle行記錄并且是每個數(shù)據(jù)塊最重要的一個部分。
.可變數(shù)據(jù)包含事務元數(shù)據(jù)
.可用空間數(shù)量可以通過行數(shù)據(jù)增長與可變數(shù)據(jù)增長而減小
相關(guān)事務列表(ITLs)
內(nèi)置在每個Oracle數(shù)據(jù)塊的可以數(shù)據(jù)區(qū)域的結(jié)構(gòu)叫作相關(guān)事務列表(ITLs)。這些結(jié)構(gòu)最主要是用來負責Oracle的行級鎖與讀一致性。從高度抽象的角度來看,可以認為ITLs就像檢查框,每個檢查框與一個特定的事務相關(guān)。如果想要更新行記錄,但被鎖定的行已經(jīng)與其它事務的ITL關(guān)聯(lián),你將會收到一個TX隊列等待,這確實是行級鎖。
每個Oracle數(shù)據(jù)塊都創(chuàng)建了特定數(shù)量的ITLs。ITLs的初始值是由表的initrans空間參數(shù)所控制的并且可以通過dba_tables視圖的ini_trans列來查看。從Oracle 9i開始,缺省的ini_trans值為1,然而通過簡單的塊dump可以清楚的看到創(chuàng)建了兩個ITL。使用兩個ITLs,單個數(shù)據(jù)塊可以同時并發(fā)地執(zhí)行兩個事務。
假設(shè)第三個事務想要修改塊中沒有被鎖定的行而只在兩個ITL存在時,第三個事務的服務器進程將嘗試動態(tài)創(chuàng)建一個額外的ITL。然而服務器進程必須首先確保ITL的最大數(shù)(max_trans)不會被超過并且在數(shù)據(jù)塊中要有可用空間。如果服務器進程不能創(chuàng)建額外的ITL,它將發(fā)出一個TX隊列等待事件,并且這個進程將耐心等待。為了減小這種情況的出現(xiàn),單個塊的ITLs的缺省值與最大值都可以設(shè)置為255。當不超過這個值時可以執(zhí)行alter table命令來修改。
一旦在數(shù)據(jù)塊中創(chuàng)建了一個ITL后,唯一能獲得空間的方式是重新創(chuàng)建整個表。修改空間參數(shù)將不會影響已經(jīng)創(chuàng)建的ITL。這就是為什么缺省的ITLs為1(實際上創(chuàng)建了兩個ITL)并且最大值設(shè)置為255的原因。如果數(shù)據(jù)塊的并發(fā)請求更多的ITLs,Oracle寧愿消耗空間也不愿意發(fā)出TX隊列等待事件而讓事務等待。
初看,ITL的最大數(shù)是255可能看上去非常有限,但請考慮這種情況:想想在最高并發(fā)應用程序中,在最高并發(fā)的數(shù)據(jù)庫中的最高并發(fā)表。也許有一個表可能有250個并發(fā)進程正在更新,刪除與插入記錄。現(xiàn)在真正有多少進程將會并發(fā)更新,刪除或插入記錄到一個數(shù)據(jù)塊中,而不是整個表或區(qū),是單個塊。即使使用最高并發(fā)性的應用程序,在一個塊中激活超過255個并發(fā)事務也是極不可能的。所以ITL的最大數(shù)255并沒有太大的限制。然而如果確實出現(xiàn)了問題,可以通過增加表的pct_free參數(shù)來減小數(shù)據(jù)塊的并發(fā)性或者為了減少存儲在塊中的行記錄可以增加固定長度的列。
Unod段的事務表
每個undo段在它的頭塊中包含一個結(jié)構(gòu)叫事務表。Oracle開發(fā)人員將事務表中的行稱作slots(插槽)。每一個已經(jīng)占用的slot都與正在或已經(jīng)在undo段中存儲undo信息的事務相關(guān)。如果一個事務已經(jīng)提交或者回滾,它確實是一個非活動事務,否則它就是一個活動事務。除了包含slot號與事務狀態(tài),每個slot也包含一個序列號。為了區(qū)分不同的事務使用相同的slot并能讓slot重用,序列號可以增長。UBA是undo塊地址,提供到事務的undo的直接鏈接。SCN是當相關(guān)事務開始時事務的系統(tǒng)改變號。
事務表與性能分析人員相關(guān)因為它們提供了事務號。每個事務有一個相關(guān)的事務號,并且事務號是基于事務的事務表條目生成的。事務號由三組數(shù)字組成。第一部分是事務表號,第二部分是slot號,最后是相關(guān)序列號。例如,一個事務號為00100.000.00007。ITLs與事務表之間的聯(lián)系是每個ITL條目關(guān)聯(lián)到一個特定的事務并且在ITL條目中包含事務號,比如00100.000.00007。
深入了解相關(guān)事務列表(ITL)
已經(jīng)了解了ITL與undo段事務表,現(xiàn)在是將它們作為單個工作單元組合在一起的時候了,并展示在事務活動期間ITLs是如何變化的。深入了解相關(guān)事務列表可以讓你深入理解Oracle如何管理事務并發(fā)性,如何創(chuàng)建讀一致性塊以及為什么要小心“snapshot too old”錯誤。
下面通過執(zhí)行命令alter system dump datafile 1 block 75847來dump數(shù)據(jù)塊。在執(zhí)行塊dump時,這個塊(1,75847)包含了許多行記錄并且有三個活動事務更新四行不同的記錄。第一個與第三個事務顯示正在更新一行記錄,第二個事務正在更新二行記錄。
$ cat prod5_ora_21741.trc ... Block header dump: 0x00412847 Object id on Block? Y seg/obj: 0xff6b csc: 0x00.50fcb6 itc: 3 flg: O typ: 1 - DATA fsl: 0 fnx: 0x412848 ver: 0x01 Itl Xid Uba Flag Lck Scn/Fsc 0x01 0x0003.00d.00000318 0x00c3e3d0.0593.0c ---- 1 fsc 0x0000.00000000 0x02 0x0008.01b.00000340 0x00c41bce.0481.24 ---- 2 fsc 0x0000.00000000 0x03 0x0001.000.00000320 0x00c45fa0.0599.0b ---- 1 fsc 0x0000.00000000 ...
ITL條目包含以下內(nèi)容:
itl:這是事務的ITL號
xid:這是事務ID,它由事務表ID(0003),事務表slot號(00d)與序列號(00000318)組成。事務ID是很重要的,因為它用于確保看起來相關(guān)的undo信息是真正相關(guān)的。
uba:這是undo塊地址。這直接指向事務的最新更改undo,對于回滾事務和讀取一致性(克隆緩沖區(qū)構(gòu)造)都是必要的。
flag:事務的狀態(tài)它可以有許多值,以下是常見值
----- 意味著事務是活動的,DML在執(zhí)行事務沒有提交或回滾
--U-- 意味著事務已經(jīng)提交,因此任何行數(shù)據(jù)都可以引用在活動事務中沒有被使用的ITL并且它們沒有被鎖定。事務的行數(shù)據(jù)可能沒有被合并。例如,如果一個列被更新,在更改之前與之前的值可能保留在行數(shù)據(jù)中。
--C-- 意味著事務已經(jīng)提交,行數(shù)據(jù)已經(jīng)合并,并且行數(shù)據(jù)中的ITL條目已經(jīng)被刪除。任何塊touch可能觸發(fā)對這個flag的改變,包括select語句。我知道這很難相信。這種看似延遲的更改通常稱為延遲塊清除,或者簡單地稱為塊清除。
Lck:這是事務在某個時刻鎖定在這個塊中的行數(shù)。大于0的值不能夠說時行被鎖定。如果這個值為2,就像第二個事務一樣,這個事務關(guān)聯(lián)兩行記錄。鎖會保持到flag改變?yōu)镃----為止。這意味著在一個事務提交后且不再被認為是活動(--U--)狀態(tài)時,Lck值可能大于0
Scn/Fsc:SCN是系統(tǒng)改變號并用來判斷事務是何時結(jié)束的(提交或回滾)。上面的例子中SCN沒有被指泒,但在事務提交后,SCN被設(shè)置了如下所示。當創(chuàng)建一個buffer的讀一致性版本判斷是否需要檢索undo時SCN是很重要的。FSC引用可用空間信用。它用于未提交的事務當一個更新或刪除操作造成行記錄長度收縮使用。Oracle將保護這個空閑空間,以防事務回滾和需要重新填充空間。如果空閑空間用于其他用途,然后事務回滾,則可能需要遷移行!。在下面的dump結(jié)果中,前兩個事務(ITLs x01與x02)已經(jīng)提交標記它們的事務為非活動狀態(tài)。第三個事務,ITL x03,還沒有提交。在前兩個事務提交后,相同的塊dump命令,alter system dump datafile 1 block 75847。注意flag已經(jīng)改變了,一個SCN已經(jīng)指泒給事務了。
$ cat prod5_ora_21741.trc ... Block header dump: 0x00412847 Object id on Block? Y seg/obj: 0xff6b csc: 0x00.50fcb6 itc: 3 flg: O typ: 1 - DATA fsl: 0 fnx: 0x412848 ver: 0x01 Itl Xid Uba Flag Lck Scn/Fsc 0x01 0x0003.00d.00000318 0x00c3e3d0.0593.0c --U- 1 fsc 0x0000.0050fd6f 0x02 0x0008.01b.00000340 0x00c41bce.0481.24 --U- 2 fsc 0x0000.0050fd6b 0x03 0x0001.000.00000320 0x00c45fa0.0599.0b ---- 1 fsc 0x0000.00000000
兩個flags ----與--U-是必需的,因為活動事或者過去的活動事務中涉及的行可以在其行數(shù)據(jù)中具有有效的ITL條目。因為簡單引用行數(shù)據(jù)與查看ITL條目不能說明行當前被活動事務調(diào)用與鎖定。為了檢查行是否被鎖定,一個服務器進程必須從行數(shù)據(jù)中得到ITL引用然后檢查數(shù)據(jù)塊的可變ITL區(qū)域中的flag。如果flag為 ----,那么服務器進程知道行確實被一個活動事務所調(diào)用且被鎖定。然而如果falg為--U,服務器進程知道行沒有被鎖定。
塊清除進程的部分工作將刪除非活動事務行數(shù)據(jù)ITL條目,將它們各自的ITL條目在數(shù)據(jù)塊的可變部分的flag的狀態(tài)修改為C---,并合并行數(shù)據(jù)。
這是一種聰明的策略,因為Oracle可以快速使用最小的改變來記錄數(shù)據(jù)塊中的改變,但仍然在行級別維護并發(fā)控制。最終需要對塊進行最后的更改,但這可能發(fā)生在工作負載較低的時期,比如基準測試完成之后。
執(zhí)行查詢語句來touch塊1,75847后,再執(zhí)行dump命令的結(jié)果如下,數(shù)據(jù)塊(1,75847)在執(zhí)行查詢語句touch數(shù)據(jù)塊后事務flags從--U-變?yōu)榱薈---,指示塊清除已經(jīng)發(fā)生了。
$ cat prod5_ora_21741.trc ... Block header dump: 0x00412847 Object id on Block? Y seg/obj: 0xff6b csc: 0x00.510047 itc: 3 flg: O typ: 1 - DATA fsl: 0 fnx: 0x412848 ver: 0x01 Itl Xid Uba Flag Lck Scn/Fsc 0x01 0x0003.00d.00000318 0x00c3e3d0.0593.0c C--- 0 scn 0x0000.0050fd6f 0x02 0x0008.01b.00000340 0x00c41bce.0481.24 C--- 0 scn 0x0000.0050fd6b 0x03 0x0001.000.00000320 0x00c45fa0.0599.0b ---- 1 fsc 0x0000.00000000 ...
現(xiàn)在我意識到這很有趣,但是我也理解一些讀者可能認為這個block dump和ITL的東西并沒有那么強的關(guān)聯(lián)。但我不敢茍同。您不僅對TX排隊有了更全面的了解,而且還清楚地了解了如何排隊Oracle實現(xiàn)了它的專利行級鎖方案。
深入了解Buffer克隆
介紹塊克隆是因為它與CBC latch競爭。現(xiàn)在將深入學習Oracle如何使用ITLs,undo塊,SCNs與其它有趣的Oracle技術(shù)。當一個服務器進程要定位一個請求的buffer并且發(fā)現(xiàn)請求的行在查詢開始后發(fā)生改變了,它必須為buffer創(chuàng)建一個時光倒流的鏡像。這就叫作當前(CU)buffer的一致性讀(CR)buffer。一旦buffer被拷貝,合適的undo被應用后,使被拷貝的buffer回退直到CR buffer被成功克隆好為止。
假設(shè)我們的查詢執(zhí)行時間是SCN 12330,查詢最終得到要訪問的buffer 7,678。然而,我們注意到存在一些ITL活動事務 7.3.8當前是活動狀態(tài)并且buffer可能在我們查詢開始后發(fā)生了改變。事務5.2.6是非活動狀態(tài)(flag為C,并指派了SCN,并且Lck為0),但是改變的提交時間在我們查詢開始之后并且影響這個當前(CU)buffer。這些塊改變意味著在CU buffer在我們查詢在SCN 12330時間點開始后已經(jīng)發(fā)生改變了并且不能用于我們的查詢。我們需要一個一致性讀副本,它可以時光倒流回到SCN 12330時間點。因此CU buffer 7,678必須被克隆并應用undo,來創(chuàng)建一個SCN12330時間點的CR buffer。
在執(zhí)行buffer克隆之前,必須找到一個不被頻繁訪問的free buffer然后使用7,678的CU buffer來替換它。服務器進程將獲得LRU chain latch與相關(guān)的LRU chain,然后從LRU chain的LRU端開始掃描,查找不被頻繁訪問的free buffer。最終將找到一個不被頻繁訪問的free buffer并使用CU buffer 7,678的副本來替換它。當然CBC結(jié)構(gòu)也將被更新來映射克隆buffer在buffer cache中的位置。
從與第一個ITL相關(guān)的活動事務7.3.8開始。服務器進程需要檢索在我們查詢開始時間scn 12330之后所有生成的undo記錄。事務7.3.8的最近生成的undo可以通過它的ITL的undo塊地址(UBA)所鏈接到的undo塊2,45中找到。服務器進程然后必須訪問undo塊2,45。這需要請求CBC活動并且也可能請求LRU活動來執(zhí)行IO調(diào)用。一旦訪問到undo buffer 2,45,將會通過比較事務號來檢查確保我們使用正確的事務在工作。數(shù)據(jù)塊與undo塊事務號需要匹配(7.3.8),因為事務是活動的,所以undo信息應該沒有鋪覆蓋。
undo塊2,45的SCN是12348,這意味著undo塊代表的塊改變出現(xiàn)在我們查詢開始時間scn 12330之后,因此,我們需要對克隆的CR buffer應用undo數(shù)據(jù),讓它回退到過去一點點。
undo塊2,45也鏈接到了另一個undo塊2,90。這是一種undo鏈并且可能持續(xù)一段時間,消耗大量的計算資源。服務器進程現(xiàn)在必須訪問undo塊2,90(請求CBC活動并且也可能請求LRU活動來執(zhí)行IO調(diào)用)并且再次比較事務號來確保它們是否匹配。它們匹配,現(xiàn)在檢查SCN。undo塊2,90的SCN是12320,它在我們的查詢開始時間SCN 12330之前,因此我們不需要應用undo。如果不應用undo,我們的CR buffer將代表的是塊7,678在SCN 12320時間點的版本,這比我們要查詢的時間SCN 12330早了。
現(xiàn)在查看第二個ITL,它與事務5,2.6關(guān)聯(lián)。這個事務在SCN 12350時間點已經(jīng)提交了,在我們的查詢開始時間之后,因此我們需要應用它的undo。從ITL條目來看,我們將得到ndo塊地址2,70并且訪問這個undo塊。現(xiàn)在比較事務號,因為事務已經(jīng)提交,undo信息將不再受保護。增加undo保留期可以讓udno信息保留更長的境,但也不受保護。
假設(shè)另一個服務器進程覆蓋了undo塊2,70中的相關(guān)事務undo信息。如果出現(xiàn)這種情況,服務器進程的事務號將被記錄并且這里將記錄為5.2.6。通過事務號比較,我們注意到差異并且立即知道undo塊2,70中的undo不能應用于我們的CR buffer。在這時,服務器進程將會發(fā)出快照太舊的錯誤信息并停止我們的查詢。很明顯,undo塊快照太舊因為被其它進程覆蓋了。
幸運地是,事務號是匹配的。undo塊2,70中的undo是在SCN 12340時間點發(fā)生的改變,它在我們的查詢開始之后,因此我們應用這個undo到我們的CR buffer。下一個undo鏈接是空的,因此沒有其它undo需要應用了。
現(xiàn)在返回到ITL條目,這里沒有更多的ITL需要考慮,因此我們完成的數(shù)據(jù)塊的克隆。任何一個服務器進程現(xiàn)在都可以訪問CR buffer 7,678它包含了SCN 12330時間所代表的內(nèi)容。
現(xiàn)在應該很清楚為什么ITLs如此重要了,而且Oracle的讀取一致性模型雖然非常強大、必要且高效,但仍然相對昂貴,因為它可能會消耗大量CPU和IO,從而減慢應用程序的響應時間。Oracle非常清楚這一點,并且從Oracle 10gr2開始使用內(nèi)存優(yōu)化結(jié)構(gòu)來臨時存儲undo信息。這些對象不是段類型并且不受與段相關(guān)的CBC和LRU chain活動的影響。在內(nèi)存中,undo被存儲在shared pool中。
新聞名稱:OracleEnqueueWaits
文章位置:http://chinadenli.net/article14/ppdhge.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號、網(wǎng)站設(shè)計、網(wǎng)站策劃、品牌網(wǎng)站設(shè)計、網(wǎng)站導航、外貿(mào)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)