產生TX鎖等待不同情形的分析

sqysl發表於2009-01-28

本文給出與TX鎖等待有關的幾個例子。一般情況下,這些等待並不顯著,除非它們執行的時間特別長,或者導致死鎖(ORA-60錯誤)。本文給出的例子面向應用人員和DBA。例子的測試環境需要對V$檢視的select許可權。 
  1. 有用的sql語句
  如果遇到一個鎖相關的hang的情形,可以使用下述語句,來幫助我們找出waiters和blockers:
  顯示等待鎖的所有會話:
  select event,p1,p2,p3 from v$session_wait
  where wait_time=0 and event='enqueue';
  顯示等待TX鎖的所有會話:
  select * from v$lock where type='TX' and request>0;
  顯示持有TX鎖的所有會話:
  select * from v$lock where type='TX' and lmode>0;
   2. 什麼是TX鎖
  當一個事務開始首次更改的時候,要求持有TX鎖,直到事務執行一個COMMIT 或者 ROLLBACK。它利用的是 排隊機制,其他的會話只能等待此事務結束。
  TX鎖的名稱(ID1 和 ID2)反映了活動事務ID。
   3. 例子
  使用下面的表來說明問題:
  以SCOTT/TIGER身份或者其他的測試使用者連線資料庫,並搭建好測試環境:
  DROP TABLE tx_eg;
  CREATE TABLE tx_eg ( num number, txt varchar2(10), sex varchar2(10) )
  INITRANS 1 MAXTRANS 2;
  INSERT into tx_eg VALUES ( 1, 'First','FEMALE' );
  INSERT into tx_eg VALUES ( 2, 'Second','MALE' );
  INSERT into tx_eg VALUES ( 3, 'Third','MALE' );
  INSERT into tx_eg VALUES ( 4, 'Fourth','MALE' );
  INSERT into tx_eg VALUES ( 5, 'Fifth','MALE' );
  COMMIT;
  在本例中,要求4個會話:
  Ses#1 表TX_EG使用者的第一個會話
  Ses#2 表TX_EG使用者的第二個會話
  Ses#3 表TX_EG使用者的第三個會話
  DBA SYSDBA使用者,能訪問
  例子涵蓋下述情形:
   行被一個活動事務鎖定
   唯一性約束或者主鍵約束
   塊頭中的事務槽不夠
   同一點陣圖索引涉及到多行
  4. 行被一個活動事務鎖定
  當一個會話更新表中的行的時候,該行會被會話的事務鎖定。其他使用者可能會使用select查詢此行,但是看到的是在更新前的行。如果另外一個會話也希望更新此行,它必須等待第一個會話提交或回滾。第二個會話以獨佔模式,等待第一個會話釋放佔用的TX鎖。
  例如:
  Ses#1: update tx_eg set txt='Garbage' where num=1;
  Ses#2: update tx_eg set txt='Garbage' where num=1;
  DBA: select SID,TYPE,ID1,ID2,LMODE,REQUEST
  from v$lock where type='TX';
  SID TY ID1 ID2 LMODE REQUEST
  ---------- -- ---------- ---------- ---------- ----------
  8 TX 131075 597 6 0
  10 TX 131075 597 0 6
   SID 10等待TX SID 8持有的TX鎖,並且希望以獨佔模式佔有此TX鎖 (as REQUEST=6)。
  下面的查詢,演示了當出現一個TX鎖等待的時候,在V$SESSION_WAIT中顯示一個'enqueue',P1RAW, P2 和 P3顯示了實際的被等待的鎖。當使用並行 伺服器,event是'DFS enqueue lock acquisition',而不是'enqueue'。
  DBA: select sid,p1raw, p2, p3
  from v$session_wait
  where wait_time=0 and event='enqueue';
  SID P1RAW P2 P3
  ---------- -------- ---------- ----------
  10 54580006 131075 597
  > ~~~~ ~~ ~~~~~~ ~~~
  > type|mode id1 id2
  > T X 6 131075 597
  另一個查詢顯示object_id和會話等待的具體行。該資訊在V$SESSION中僅僅當會話等待是行級鎖才有效。該查詢從Oracle 7.3開始可用。上述示例中,SID 10是等待者:
  DBA: select ROW_WAIT_OBJ#,
  ROW_WAIT_FILE#,ROW_WAIT_BLOCK#,ROW_WAIT_ROW#
  from v$session
  where sid=10;
  ROW_WAIT_O ROW_WAIT_F ROW_WAIT_B ROW_WAIT_R
  ---------- ---------- ---------- ----------
  3058 4 2683 0
  > 等待者正在等待一個TX 鎖,它鎖定檔案4中的2683塊中的第0行,物件號是3058.
  Ses#1: rollback;
  Ses#2: rollback;
   5. 唯一性約束或者主鍵約束
  如果一個表有主鍵約束,或者唯一性約束,或者唯一性索引,那麼該約束引用的列的唯一性由唯一性索引啟用。如果兩個會話想插入同一個鍵值,第二個會話必須等待,以便知道是否會產生ORA-0001錯誤。
  例如:
  Ses#1: ALTER TABLE tx_eg ADD CONSTRAINT tx_eg_pk PRIMARY KEY( num );
  Ses#1: insert into tx_eg values (10,'New','MALE');
  Ses#2: insert into tx_eg values (10,'OtherNew',null);
  DBA: select SID,TYPE,ID1,ID2,LMODE,REQUEST
  from v$lock where type='TX';
  SID TY ID1 ID2 LMODE REQUEST
  ---------- -- ---------- ---------- ---------- ----------
  8 TX 196625 39 6 0
  10 TX 262155 65 6 0
  10 TX 196625 39 0 4
  SID 10等待SID 8持有的TX鎖,並想將此鎖置於共享模式(REQUEST=4)。SID 10事務本身持有一個TX鎖。
  Ses#1: commit;
  Ses#2: ORA-00001: unique constraint (SCOTT.TX_EG_PK) violated
  Ses#2: rollback;
  6. 塊中的事務槽不夠
  Oracle利用每個資料塊中的頭部資訊,來標識哪些事務鎖定了哪些行,這就是'interested transaction list'
  一個物件中的事務的ITL數量,由屬性INITRANS 和 MAXTRANS控制。INITRANS是初始事務槽數量。MAXTRANS是允許的最多的事務槽數量。每個想要修改塊的事務,都需要佔用塊的一個'ITL'。
  MAXTRANS決定了在一個塊中,最大活動的併發事務數。
  INITRANS 為最小的併發事務數。如果要求的事務數介於INITRANS和MAXTRANS,ITL會自動擴充套件,前提是在塊的頭部還有足夠的剩餘空間,用於存放擴充套件ITL的資訊。
  如果沒有可用的'ITL',那麼會話就會以模式4等待一個活動事務的TX鎖。
  例如:
  Ses#1: update tx_eg set txt='Garbage' where num=1;
  Ses#2: update tx_eg set txt='Different' where num=2;
  Ses#3: update tx_eg set txt='Different' where num=3;
  DBA: select SID,TYPE,ID1,ID2,LMODE,REQUEST
  from v$lock where type='TX';
  SID TY ID1 ID2 LMODE REQUEST
  ---------- -- ---------- ---------- ---------- ----------
  8 TX 655367 560 6 0
  10 TX 655367 560 0 4
  12 TX 458799 551 6 0
  SID 10等待SID 8持有的TX鎖,並想將此鎖置於共享模式(REQUEST=4)。
  Ses#1: commit;
  Ses#2: commit;
  Ses#3: commit;
  Ses#1: ALTER TABLE tx_eg MAXTRANS 3;
  Ses#1: update tx_eg set txt='First' where num=1;
  Ses#2: update tx_eg set txt='Second' where num=2;
  Ses#3: update tx_eg set txt='Different' where num=3;
  三行都可以更新,因為有可用的空間用於ITL列表進行增長,以滿足三個事務的要求。
  Ses#1: commit;
  Ses#2: commit;
  Ses#3: commit;
  從9.2開始,可以使用v$segment_statistics來檢查ITL等待:
  SELECT t.OWNER, t.OBJECT_NAME, t.OBJECT_TYPE, t.STATISTIC_NAME, t.VALUE
  FROM v$segment_statistics t
  WHERE t.STATISTIC_NAME = 'ITL waits'
  AND t.VALUE > 0;
  OWNER OBJECT_NAME OBJECT_TYPE STATISTIC_NAME VALUE
  ------- ------------ ------------ --------------- -----
  HR TX_EG TABLE ITL waits 1
  必要時,可以增大INITTRANS 和 MAXTRANS
   7. 同一點陣圖索引涉及到多行
  點陣圖的鍵值對應一個範圍內的ROWID。每個點陣圖索引的入口可能對應實際表中的多行。
  如果兩個會話希望更新同一個點陣圖索引片段對應的行,那麼第二個會話就會以共享模式等待TX鎖,直到第一個會話提交或者回滾。
  例如:
  Ses#1: CREATE Bitmap Index tx_eg_bitmap on tx_eg ( sex );
  Ses#1: update tx_eg set sex='FEMALE' where num=3;
  Ses#2: update tx_eg set sex='FEMALE' where num=4;
  DBA: select SID,TYPE,ID1,ID2,LMODE,REQUEST
  from v$lock where type='TX';
  SID TY ID1 ID2 LMODE REQUEST
  ---------- -- ---------- ---------- ---------- ----------
  8 TX 262151 62 6 0
  10 TX 327680 60 6 0
  10 TX 262151 62 0 4
  SID 10等待SID 8持有的TX鎖,並想將此鎖置於共享模式(REQUEST=4)。
  Ses#1: commit;
  Ses#2: commit;
   8. 其他情形
  其他情形比較少見。

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

相關文章