位图索引(bitmap index)冲突引起的TX锁争用
下面做一個測試:
打開一個會話1:
SQL> select sid from v$mystat where rownum<2;
? ? ? ?SID
----------
? ? ? ?148
SQL> create table tx_b(name1 char(10),name2 char(10),name3 char(10));
表已創(chuàng)建。
SQL> create bitmap index tx_b_idx on tx_b(name1,name2,name3);
索引已創(chuàng)建。
SQL> insert into tx_b values('a','b','c');
已創(chuàng)建 1 行。
新打開一個會話2:
SQL> select sid from v$mystat where rownum<2;
? ? ? ?SID
----------
? ? ? ?141
SQL> insert into tx_b values('a','b','c');
一直處于等待狀態(tài)
再打開一個會話3:
SQL> select * from v$lock where type='TX'; ?
ADDR ? ? ? ? ? ? ?KADDR ? ? ? ? ? SID ? ?TY ? ? ? ?ID1 ? ? ? ? ? ?ID2 ? ? ? LMODE ? ?REQUEST? ? ?CTIME ? ? ?BLOCK
-------- ? ? ? ? ? ? ?-------- ? ? ? ? ? ?---------- -- ? ? ?---------- ? ---------- ? ---------- ? ? ---------- ? ? ? ? ? ??---------- ----------
6C26DA0C ?6C26DB20 ? ? ? ?141 ? TX ? ? 327684 ? ? ? 3452 ? ? ? ? ?6 ? ? ? ? ? ? 0? ? ? ? ? ? ? ? ? ? ?111 ? ? ? ? ? ?0
6CA63958 ?6CA6396C ? ? ? ?141 ? ? TX ? ? 262181 ? ? ?14897 ? ? ? ? ?0 ? ? ? ? ? ? 4? ? ? ? ? ? ? ? ? ?111 ? ? ? ? ? ?0
6C2953FC ?6C295510 ? ? ? ?148 ? ?TX ? ? 262181 ? ? ?14897 ? ? ? ? ?6 ? ? ? ? ? ? 0? ? ? ? ? ? ? ? ? ? ? 216 ? ? ? ? ?1
這個結(jié)果與唯一鍵沖突引起的等待現(xiàn)象完全相同。只通過等待現(xiàn)象,不能區(qū)別唯一鍵沖突和位圖索引沖突之間的差異,只有在同時考慮到創(chuàng)建索引的準(zhǔn)確信息和sql語句,才能掌握準(zhǔn)確的原因。
索引葉節(jié)點(diǎn)(leaf node)上發(fā)生分割時,相關(guān)的等待時間是enq:TX-index contention
B*Tree索引在添加數(shù)據(jù)的過程中,如果葉節(jié)點(diǎn)已滿就會進(jìn)行分割(split),以此到大平衡,會話A在exclusive模式已獲得TX鎖的情況下,執(zhí)行分割的過程中,會話B正要修改葉節(jié)點(diǎn)時,會話B為了以shared模式獲得會話A擁有的TX鎖只好等待,在此期間會發(fā)生enq:TX-index contention等待事件。
一般情況下enq:TX-index contention等待不會發(fā)生,它主要是在多個會話對已有索引的表執(zhí)行較多量的DML時發(fā)生。這個等待現(xiàn)象雖然不經(jīng)常發(fā)生,但創(chuàng)建的數(shù)量多,組成索引的列值大而指針葉節(jié)點(diǎn)的塊頻繁被分割時,成為性能下降的原因,特別是使用sequence等方式生成值的列在創(chuàng)建索引時,一直出現(xiàn)只在最后的葉節(jié)點(diǎn)添加值的現(xiàn)象,所以可能經(jīng)常發(fā)生索引分割。這是以排序形式保持葉節(jié)點(diǎn)的B*Tree 索引屬性引起的,因此多個會話將大量的數(shù)據(jù)執(zhí)行insert 時,與buffer busy waits 等待一起發(fā)生enq:TX-index contention等待。
減少索引分割引發(fā)的爭用的基本方法,就是阻止在相同的葉節(jié)點(diǎn)塊里集中添加數(shù)據(jù)的現(xiàn)象,例如可以應(yīng)用partitioning方法進(jìn)行物理分散,或是修改該組成索引的列的順序而自然分散等方法。單若存在以特定鍵為基準(zhǔn)排序這樣的約束條件,就無法使用此方法。具有代表性的情況是利用sequence賦予主鍵值,利用/*INDEX_DESC*/ 之類的提示,對此索引以排序的方式執(zhí)行掃描數(shù)據(jù)查詢。通過這種方式使用索引時,必須保障相應(yīng)鍵為基準(zhǔn)排序,所以不能在索引上應(yīng)用partitioning或修改該索引的列順序。
另一種方法是將索引的塊設(shè)定的較大。使用較大的塊時,一個塊上的條目數(shù)量多,因此較少發(fā)生分割。但是若塊大小增加,就可能引發(fā)buffer lock 爭用引起的buffer busy waits 等待現(xiàn)象,所以要謹(jǐn)慎使用。
請注意一點(diǎn),修改沒有創(chuàng)建索引的表過程中,有時能發(fā)生enq:TX-index contention等待。表里有l(wèi)ob列時,就會從內(nèi)部創(chuàng)建對于LOB數(shù)據(jù)的索引(稱為LOB索引)因此多個會話同時修改LOB數(shù)據(jù)時會發(fā)生索引爭用。
)其他情況時,相關(guān)的等待時間是enq:TX-contention
***分布式事務(wù)(distributed transaction)環(huán)境下,通過prepared transaction讀取已獲得鎖的行時,知道事務(wù)結(jié)束為止,為了一shared 模式獲取TX鎖而需要等待。
***將FLM以段空間管理方法使用時,想要分配TFL(transaction free list)的進(jìn)程無法分配到TFL時,為了一shared 模式獲得已經(jīng)占有TFL的事務(wù)的TX鎖,需要等待。
***回滾段頭的事務(wù)表上西藥分配新的slot時,應(yīng)該以exclusive模式獲得TX鎖。
enq:UL-contention ?PL/SQL lock Timer
使用DBMS_LOCK程序包,可以對任意假想的資源掛起鎖,如果是因?yàn)镈ML發(fā)生的鎖時,雖然必須需要物理資源(表,事務(wù),段等),但使用DBMS_LOCK程序包沒有這種限制,使用DBMS_LOCK程序包獲取鎖稱為UL(Userdefined ?Lock)鎖,為了獲得UL鎖 而等待的會話,將發(fā)生enq:UL-contention等待事件。
利用DBMS_LOCK.REQUEST函數(shù)可以將UL鎖以Exclusive模式獲得,利用DBMS_LOCK.RELEASE函數(shù),可以釋放鎖。記住UL鎖的釋放只能在擁有鎖的會話上實(shí)現(xiàn),若特定會話因長時間擁有UL鎖,而引發(fā)并發(fā)性問題,則除了強(qiáng)制結(jié)束會話之外沒有其他方法。使用DBMS_LOCK.REQUEST函數(shù)時,盡量使用RELEASE_ON_COMMIT選項(xiàng),以避免多余的擁有鎖,使用這個選項(xiàng)若發(fā)生提交或回滾,則自動釋放該事務(wù)所擁有的UL鎖。
另外,還有一個與DBMS_LOCK程序包相關(guān)的等待事件,利用DBMS_LOCK.SLEEP Procedure 暫時中斷事務(wù)時,則該進(jìn)程等待PL/SQL lock timer事件。
PL/SQL lock timer 等待事件不會引起性能的問題。如果該等待時間比預(yù)期還要長,就應(yīng)該重新檢查應(yīng)用程序的實(shí)現(xiàn)邏輯是否有問題。
以下查詢,可以查詢出在位圖索引上的等待事件:
注意:位圖索引在位圖的段級別上(而不是在行級別上)設(shè)置鎖。如果對位圖索引中的一列進(jìn)行更新,行級鎖將會出問題。
總結(jié)
以上是生活随笔為你收集整理的位图索引(bitmap index)冲突引起的TX锁争用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学习笔记:ORACLE 性能优化求生指南
- 下一篇: 发生TM锁争用的情况