ログマイナー再び!! その4

投稿日: 2007年10月17日

<ログマイナー再び!! その4>
ペンネーム: ぽっちゃりメタボン

こんにちは!!、ぽっちゃりメタボンです。
めっきり茅ヶ崎も寒くなってきましたが、今週もはりきって検証しちゃうぞー。

▼ 前回のおさらい

前回は LogMiner ディクショナリとして抽出されたREDOログをダンプから確認
し、ログマイナー関連の表に対するDMLが実行されていることを確認しました。

気になるのはどういったSQL文がdbms_logmnr_d.build プロシージャ実行時
に流れているのかですが、今回は SQL Trace を使用して、確認します。

▼ 環境のおさらい

OS:Red Hat Enterprise Linux ES release 3
DB:10gR2(10.2.0.1)

▼ SQL Trace を取得

1. セッション単位で SQL Trace を有効にします。

SQL> alter session set sql_trace=true;

セッションが変更されました。

2. ディクショナリをアーカイブREDOログへ抽出します。

SQL> execute dbms_logmnr_d.build(options=> -
          dbms_logmnr_d.store_in_redo_logs);

PL/SQLプロシージャが正常に完了しました。

トレースファイルが初期化パラメータ user_dump_dest へ出力されているの
で早速、確認してみましょう。

さて、どのようなSQL文が実行されているのでしょうか。

▼ トレースを眺めてみるのだ!!

トレースファイルからSQL文のみを抽出します。

$ egrep -v "^*|^XCTEND|^EXEC #|^PARS|^FETCH|^STAT|^END|^=" 
  ora102_ora_1712.trc>/home/ora102/sql.txt

抽出した内容をシーケンシャルにまとめたものが以下となります。

トレースファイルより抜粋———————————————

1. ディクショナリのロック

LOCK TABLE SYS.OBJ$, SYS.TAB$, SYS.COL$, SYS.ATTRCOL$, SYS.TS$,
SYS.IND$, SYS.USER$, SYS.TABPART$, SYS.TABSUBPART$,
SYS.TABCOMPART$, SYS.TYPE$, SYS.COLTYPE$, SYS.ATTRIBUTE$,
SYS.LOB$, SYS.CDEF$, SYS.CCOL$, SYS.ICOL$, SYS.LOBFRAG$,
SYS.INDPART$, SYS.INDSUBPART$, SYS.INDCOMPART$
IN SHARE MODE NOWAIT

2. カレントREDOログの変更

ALTER SYSTEM SWITCH ALL LOGFILE

3. LogMiner ディクショナリ のビルドログへINSERT
(CURRENT_BUILD_STATE = 1)

INSERT INTO SYS.LOGMNR_BUILDLOG

4. ログマイナー実行時に必要となる情報を収集し、INSERT
※()内はinsert情報収集元となります。
INSERT INTO LOGMNRG_SEED$
(SYS.OBJ$,SYS.TAB$,SYS.COL$,SYS.USER$)
INSERT INTO SYS.LOGMNRG_DICTIONARY$
(SYS.OBJ$,SYS.V$DATABASE,SYS.NLS_DATABASE_PARAMETERS,
SYS.X$KCCRT,V$INSTANCE)
INSERT INTO SYS.LOGMNRG_OBJ$ (SYS.OBJ$)
INSERT INTO SYS.LOGMNRG_TAB$ (SYS.TAB$$)
INSERT INTO SYS.LOGMNRG_COL$ (SYS.COL$)
INSERT INTO SYS.LOGMNRG_ATTRCOL$ (SYS.ATTRCOL$)
INSERT INTO SYS.LOGMNRG_TS$ (SYS.TS$)
INSERT INTO SYS.LOGMNRG_IND$ (SYS.IND$)
INSERT INTO SYS.LOGMNRG_USER$ (SYS.USER$)
INSERT INTO SYS.LOGMNRG_TABPART$ (SYS.TABPART$)
INSERT INTO SYS.LOGMNRG_TABSUBPART$ (SYS.TABSUBPART$)
INSERT INTO SYS.LOGMNRG_TABCOMPART$ (SYS.TABCOMPART$)
INSERT INTO SYS.LOGMNRG_TYPE$ (SYS.TYPE$)
INSERT INTO SYS.LOGMNRG_COLTYPE$ (SYS.COLTYPE$)
INSERT INTO SYS.LOGMNRG_ATTRIBUTE$ (SYS.ATTRIBUTE$)
INSERT INTO SYS.LOGMNRG_LOB$ (SYS.LOB$)
INSERT INTO SYS.LOGMNRG_CDEF$ (SYS.CDEF$)
INSERT INTO SYS.LOGMNRG_CCOL$ (SYS.CCOL$)
INSERT INTO SYS.LOGMNRG_ICOL$ (SYS.ICOL$)
INSERT INTO SYS.LOGMNRG_LOBFRAG$ (SYS.LOBFRAG$)
INSERT INTO SYS.LOGMNRG_INDPART$ (SYS.INDPART$)
INSERT INTO SYS.LOGMNRG_INDSUBPART$ (SYS.INDSUBPART$)
INSERT INTO SYS.LOGMNRG_INDCOMPART$ (SYS.INDCOMPART$)

5. 収集した情報をTRUNCATE

TRUNCATE TABLE SYS.LOGMNRG_ATTRCOL$
TRUNCATE TABLE SYS.LOGMNRG_ATTRIBUTE$
TRUNCATE TABLE SYS.LOGMNRG_CCOL$
TRUNCATE TABLE SYS.LOGMNRG_CDEF$
TRUNCATE TABLE SYS.LOGMNRG_COL$
TRUNCATE TABLE SYS.LOGMNRG_COLTYPE$
TRUNCATE TABLE SYS.LOGMNRG_ICOL$
TRUNCATE TABLE SYS.LOGMNRG_IND$
TRUNCATE TABLE SYS.LOGMNRG_INDCOMPART$
TRUNCATE TABLE SYS.LOGMNRG_INDPART$
TRUNCATE TABLE SYS.LOGMNRG_INDSUBPART$
TRUNCATE TABLE SYS.LOGMNRG_LOB$
TRUNCATE TABLE SYS.LOGMNRG_LOBFRAG$
TRUNCATE TABLE SYS.LOGMNRG_OBJ$
TRUNCATE TABLE SYS.LOGMNRG_SEED$
TRUNCATE TABLE SYS.LOGMNRG_TAB$
TRUNCATE TABLE SYS.LOGMNRG_TABCOMPART$
TRUNCATE TABLE SYS.LOGMNRG_TABPART$
TRUNCATE TABLE SYS.LOGMNRG_TABSUBPART$
TRUNCATE TABLE SYS.LOGMNRG_TS$
TRUNCATE TABLE SYS.LOGMNRG_TYPE$
TRUNCATE TABLE SYS.LOGMNRG_USER$

6. ビルドログのUPDATE (CURRENT_BUILD_STATE = 0)

UPDATE SYS.LOGMNR_BUILDLOG

7. REDOログをアーカイブへ出力
ALTER SYSTEM ARCHIVE LOG CURRENT

抜粋—————————————————————–

メタボン(独り言・・・)>
ほうほう、こうなっているのねー。なるほど、なるほど。

以下に考察を述べます。

▼ 考察

1.)
マニュアルには「ディクショナリをREDO ログ・ストリームに抽出している
間は、DDL 文を実行できません。したがって、REDO ログ・ファイルに抽
出されるディクショナリは、一貫性が保証されます」とあります。
これは「1.ディクショナリのロック」を行い、実現している事が確認でき
ます。

先にロックが掛っていたらどうなる? ======================

他のセッションから先にディクショナリにロックをかけてから
dbms_logmnr_d.build(options=>dbms_logmnr_d.store_in_redo_logs)を
実行すると、最大600回(600秒) までロックの獲得を再試行するようです。

その後、以下のエラーが発生して実行に失敗します。

ORA-01327: ビルドに必須のシステム・ディクショナリの排他ロックに
失敗しました。

==========================================================

2.)
「2.カレントREDOログの変更」で1個、ディクショナリ情報で最低1個以
上(LogMiner ディクショナリは複数アーカイブログへ跨ることもあるため)
アーカイブログは最低2個以上出力されることが分かります。

3.)
INSERTしたデータを全てTRUNCATEしています。
よって、データを保持するためではなく更新を行うことによってREDOへの書
き込みを発生させるためだけにINSERT処理をしていると考えられます。

結果、ディクショナリ情報はアーカイブREDOログへ出力されることになりま
す。

4.)
ビルドログは以下ような構造になっています。

SQL> desc LOGMNR_BUILDLOG
名前                                      NULL?    型
----------------------------------------- -------- ------------
INITIAL_XID                               NOT NULL VARCHAR2(22)
BUILD_DATE                                         VARCHAR2(20)
DB_TXN_SCNBAS                                      NUMBER
DB_TXN_SCNWRP                                      NUMBER
CURRENT_BUILD_STATE                                NUMBER
COMPLETION_STATUS                                  NUMBER
MARKED_LOG_FILE_LOW_SCN                            NUMBER

作成日(BUILD_DATE)、実行状態(COMPLETION_STATUS 0=作成中、1=完了)等を
確認できます。
dbms_logmnr_d.build(options=>dbms_logmnr_d.store_in_redo_logs) 実行毎
に1レコード生成されるため、履歴管理の役割を持っています。

ディクショナリオプションである「REDOログへのディクショナリ抽出」に
フォーカスを当てての検証を行いましたが、如何でしたでしょうか?
内部構造を抑えた上で、運用を行えば問題発生時に対処しやすくなるのでは
ないでしょうか。

次回は、ログマイナー事前準備として、おまじないのように行った
「サプリメンタルロギング」について取り上げる予定です。

今回はここまで!!

人肌が恋しい 茅ヶ崎より