ログマイナーに関する検証 その3
< ログマイナに関する検証 その参 > ペンネーム チョビひげ
— ログ・マイナーで連鎖行を見る —
ログ・マイナーでドロップしてしまったテーブルを復旧する前に注意しなけれ
ばいけないことは以下の操作対象をログ・マイナーがサポートしていないこと
である。(Oracle8i)
・連鎖行
・索引構成表
・クラスタ化表/索引
・非スカラー型
・ダイレクト・パス・インサート
・DDL文
では、ログ・マイナーを実行したときに連鎖行はどのように表示されるのか検
証してみよう。
行連鎖は行を挿入する際に、その行のデータが大きすぎて一つのブロック内に
収まらない場合に発生する。では実際に行連鎖を発生させ、どのようにログ・
マイナーで見られるのであろうか。
1.テーブル(DOCUMENT)に以下の1件のレコード(DOCUMENT_DATAに2458Byte)を挿入
SQL> desc document; Name Null? Type --------------------------------------- -------- --------------------- DOCUMENT_ID NUMBER DOCUMENT_DATA VARCHAR2(4000) SQL> insert into document values(1,'[n*2458]'); ※[n*2458]はnが2458文字をあらわしてる
以下の手順で実際に行連鎖されているか確認してみよう。
# CHAINED_ROWS表を作成する為、UTLCHAIN.SQLを実行する
SQL> @utlchain.sql Table created.
# ANALYZEコマンドをLIST CHAINED ROWSオプションで実行
SQL> analyze table document list chained rows; Table analyzed.
# 上記のコマンドでCHAINE_ROWS表にデータが格納される
# 格納された行連鎖を検索
SQL> select table_name, head_rowid from chained_rows; TABLE_NAME HEAD_ROWID ------------------------------ ------------------ DOCUMENT AAAGW4AAFAAAR+JAAA
AAAGW4AAFAAAR+JAAAが行連鎖していることが分かる。
上記の連鎖行のINSERT文に対するREDOレコードを見てみよう。
SQL> select scn, row_id, data_obj#, operation, sql_redo, sql_undo from v$logmnr_contents; SCN ROW_ID DATA_OBJ# OPERATION SQL_REDO SQL_UNDO ------- -------------------- ---------- ---------- ------------------------ --------- 687539 AAAAAAAAAAAAAAAAAA 0 INTERNAL 687539 AAAAAAAAAAAAAAAAAA 0 INTERNAL 687539 AAAAAAAAAAAAAAAAAA 0 START set transaction read write; 687539 AAAGW4AAFAAAR+IAAA 26040 INTERNAL 687539 AAAAAAAAAAAAAAAAAA 0 INTERNAL 687539 AAAGW4AAFAAAR+JAAA 26040 INTERNAL 687541 AAAAAAAAAAAAAAAAAA 0 COMMIT commit;
上記のようにSQL_REDO列、SQL_UNDO列と共に空白になっている事がわかる。
また、ROW_IDは以下の2つのレコードが見られる。
・AAAGW4AAFAAAR+JAAA
・AAAGW4AAFAAAR+IAAA
1つのROW_ID(AAAGW4AAFAAAR+JAAA)が先程検索した行連鎖を起こしているROW_ID
と一致している。
また、ROW_ID(AAAGW4AAFAAAR+IAAA)に行連鎖していることが想像できる。
では、行移行の場合はどうなっているのか見てみたい。
まずはテーブルを作成し、1600バイトのデータを挿入し、
その後、1行のデータのUPDATEを行い、行移行を発生さる。
# テーブルからすべてのデータを削除
SQL> truncate table document; Table truncated.
# 2バイトの行データを800件挿入(document_id列は1~800で一意)
SQL> begin 2 for i in 1 .. 800 loop 3 insert into document values(i,'n'); 4 end loop; 5 end; 6 /
# document_id=2 の行のROW_IDを取得
SQL> select rowid from document where document_id=2; ROWID ------------------ AAAGYRAAFAAAR+DAAB
# document_id=2 の行のデータを1001バイトのデータにUPDATE
SQL> update document set document_data = '[n*1000]' where document_id=2; ※[n*1000]はnが1000文字をあらわしてる
# 行連鎖と同じ手順で行移行を確認
SQL> select table_name, head_rowid from chained_rows; TABLE_NAME HEAD_ROWID ------------------------------ ------------------ DOCUMENT AAAGYRAAFAAAR+DAAB
# v$logmnr_contents表を検索
SQL> select scn, seg_name, row_id, operation, sql_redo from v$logmnr_contents; SCN SEG_NAME ROW_ID OPERATION SQL_REDO -------- --------- ------------------- ---------- ---------------------- 799084 AAAAAAAAAAAAAAAAAA START set transaction read write; 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 AAAAAAAAAAAAAAAAAA INTERNAL 799084 DOCUMENT AAAGYRAAFAAAR+IAAA INSERT 799084 DOCUMENT AAAGYRAAFAAAR+DAAB DELETE Unsupported (Chained Row) 799086 AAAAAAAAAAAAAAAAAA COMMIT commit;
結果を見るとDELETEの操作で、先程検索したdocument_idが2のデータのROW_ID
を削除しているのが分かる。また親切(?)にもサポートがされてないメッセー
ジもSQL_REDO列に表示されている。またOPERATION列がINSERTの行を見ると、
行の移行先のROW_IDにインサート処理を行なっている事が確認できる。
また、v$logmnr_contents表よりデータが含まれるデータファイルおよびブロッ
ク番号も確認できる。
では、ブロック番号を指定して行移行しているブロックのダンプを見てみよう。
SQL> select scn, row_id, operation, abs_file#, data_blk# from v$logmnr_contents; SCN ROW_ID OPERATION ABS_FILE# DATA_BLK# ------- ------------------ ------------ ----------- ----------------- 799083 AAAAAAAAAAAAAAAAAA COMMIT 3 0 799084 AAAAAAAAAAAAAAAAAA START 0 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 73603 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAAAAAAAAAAAAAAAA INTERNAL 5 0 799084 AAAGYRAAFAAAR+IAAA INSERT 5 73608 799084 AAAGYRAAFAAAR+DAAB DELETE 5 73603 799086 AAAAAAAAAAAAAAAAAA COMMIT 3 0
# 行移行元のブロックダンプを作成
SQL> alter system dump datafile 5 block 73603;
# 結果
--- --- Block header dump: 0x01411f83 --- --- block_row_dump: tab 0, row 0, @0x7b0 tl: 8 fb: --H-FL-- lb: 0x0 cc: 2 col 0: [ 2] c1 02 col 1: [ 1] 6e tab 0, row 1, @0x273 tl: 9 fb: --H----- lb: 0x1 cc: 0 nrid: 0x01411f88.0 tab 0, row 2, @0x7a0 tl: 8 fb: --H-FL-- lb: 0x0 cc: 2 col 0: [ 2] c1 04 col 1: [ 1] 6e --- ---
ブロック・ヘッダー(Block header dump)を見てみると0x01411f83になっている。
また、ブロックの1行目(row 1)では列のデータが入っておらず、
nridが0x01411f88.0になっているのが分かる。
これはブロック・ヘッダーが0x01411f88の0行目(row 0)に移行していることを
指している。
では、行移行先のブロックダンプを見てみよう。
# 行移行先のブロックダンプを作成
SQL> alter system dump datafile 5 block 73608;
# 結果
--- --- Block header dump: 0x01411f88 --- --- block_row_dump: tab 0, row 0, @0x3c2 tl: 1014 fb: ----FL-- lb: 0x1 cc: 2 hrid: 0x01411f83.1 col 0: [ 2] c1 03 col 1: [999] 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e --- ---
ブロックヘッダーは0x01411f88である。
ブロックの0行目(row 0)でhridが0x01411f83.1になっているのが分かる。
これはブロック・ヘッダーが0x01411f83の1行目(row 1)から移行されているこ
とを指している。
1行のデータを得るために2ブロックにアクセスする必要があるため、
パフォーマンスに悪影響を与えることがあらためて実感できる。
次回はログ・マイナーで索引構成表をみて見てみたい。
以上、サーフィン始めよう!の茅ヶ崎にて