APPENDヒント付きの INSERT 〜 SELECT 〜 文のロック範囲が、INSERT文側のPARTITION句有無で異なる。
通常、APPENDヒント付きの INSERT 〜 SELECT文 は 排他ロック を表全体で獲得します。
例えば以下の SQL文 を別セッションから併行で実行すると、
後から実行した SQL は TM enqueue で待機します。
-- ★セッション1 INSERT /*+ APPEND */ INTO TBL_B SELECT * FROM TBL_A PARTITION(P00); 9999 rows created. -- ★セッション2 INSERT /*+ APPEND */ INTO TBL_B SELECT * FROM TBL_A PARTITION(P01); ※待たされる。 -- ★セッション3 SET LINESIZE 300; COLUMN SID FORMAT 99999; COLUMN EVENT FORMAT A40; COLUMN BINS FORMAT 999; COLUMN BSID FORMAT 99999; SELECT SID, SERIAL#, SQL_ID, EVENT, BLOCKING_INSTANCE AS BINS, BLOCKING_SESSION AS BSID FROM V$SESSION WHERE STATUS = 'ACTIVE' AND USERNAME IS NOT NULL; SID SERIAL# SQL_ID EVENT BINS BSID ------ ---------- ------------- ---------------------------------------- ---- ------ 137 2297 8c6anh1adh59k enq: TM - contention 1 202 ★TMロック待ち SET LINESIZE 300; COLUMN SESS FORMAT A20; SELECT DECODE(request,0,'Holder: ','Waiter: ') || sid sess, id1, id2, lmode, request, type FROM V$LOCK WHERE (id1, id2, type) IN (SELECT id1, id2, type FROM V$LOCK WHERE request > 0) ORDER BY id1, request; SESS ID1 ID2 LMODE REQUEST TY -------------------- ---------- ---------- ---------- ---------- -- Holder: 202 104275 0 6 0 TM ★TMロック取得済み Waiter: 137 104275 0 0 6 TM ★TMロック待ち
上記のようなケースで、INSERT文側に PARTITION句 を付与すると、ロック範囲が PARTITION単位 に 限定されるため、
APPENDヒント付きの INSERT 〜 SELECT文 を PARTITION単位で同時併行で実行できます。
-- ★セッション1 INSERT /*+ APPEND */ INTO TBL_B PARTITION(P00) SELECT * FROM TBL_A PARTITION(P00); ^^^^^^^^^^^^^^コレ 9999 rows created. -- ★セッション2 INSERT /*+ APPEND */ INTO TBL_B PARTITION(P01) SELECT * FROM TBL_A PARTITION(P01); ^^^^^^^^^^^^^^コレ 10000 rows created. -- ★セッション3 SET LINESIZE 300; SELECT sid, id1, id2, lmode, request, type FROM v$lock WHERE sid in (202, 137) ORDER BY type, id1, sid, request; SID ID1 ID2 LMODE REQUEST TY ------ ---------- ---------- ---------- ---------- -- 137 100 0 4 0 AE 202 100 0 4 0 AE 137 104275 0 3 0 TM ★104275 のTMロックを LMODE=3 で取得 ※ 202 104275 0 3 0 TM ★104275 のTMロックを LMODE=3 で取得 ※ 202 104276 0 6 0 TM ★104756 のTMロック(LMODE=6) を取得 137 104277 0 6 0 TM ★104277 のTMロック(LMODE=6) を取得 202 79833 1 3 0 TO 202 196630 6342 6 0 TX 137 458766 5920 6 0 TX 9 rows selected.
LMODE=3同士は競合しないため、ロックをお互いに取得できます。そして、ここに出て来る104275, 104276, 104277 は DBA_OBJECTS の OBJECT_ID に対応しているようです。
SELECT OBJECT_ID , OBJECT_NAME , SUBOBJECT_NAME FROM DBA_OBJECTS WHERE OBJECT_ID IN (104275, 104276, 104277); OBJECT_ID OBJECT_NAME SUBOBJECT_NAME ---------- ------------------------------ ------------------------------ 104275 TBL_B 104276 TBL_B P00 104277 TBL_B P01
表全体はLMODE=3で競合しないようにロック取得して、
パーティション単位で排他ロックを取得しているのが解ったZe!!!(`・ω・)Ъ