マテリアライズドビュー検証 まて マテ マテビュー その5

<マテリアライズドビュー検証 まて マテ マテビュー その5>
ペンネーム:クリープ

前回に引き続き高速リフレッシュについて見ていきます。
今回は、OracleのパッケージであるDBMS_MVIEW.EXPLAIN_MVIEWを使って、高速
リフレッシュの制限を確認します。
とその前に、まずは前回やり残してたcount(sal)について、見てみましょう。

■■■■■今回のあらすじ■■■■■
1)制限:count(sal)
2)DBMS_MVIEW.EXPLAIN_MVIEW

■環境
Microsoft Windows XP Pro
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 – Production

1)制限:count(sal)
※前回作成したマテビューおさらい

SQL> create materialized view mv_parttime refresh fast
     as select job, sum(sal) sum_sal, count(sal) cnt_sal, count(*) cnt_all
     from emp group by job;

まずは前回の宿題から。

上記マテビューにcount(sal)がないと、前回のcount(*)のようにUPDATE文や
DELETE文でエラーが発生するのは何故か、というのが前回の宿題でした。
この制限は、集計項目(今回の場合はsal)がNOT NULL制約でない場合のみの
制限になっています。ってことは、NULLデータが何か関係しているのかな!?

リカーシブコールを確認してみると、MERGE文で以下のような計算が行われて
いました。

※関係する箇所のみ抜粋。

WHEN MATCHED THEN UPDATE SET
SUM_SAL=DECODE(CNT_SAL+[式1], 0, NULL, NVL(SUM_SAL,0)+[式2])

[式1]
SUM(DECODE(MLOG$_EMP.OLD_NEW$$, 'N', 1, -1) * DECODE(MLOG$_EMP.SAL, NULL, 0, 1))

[式2]
NVL(SUM(DECODE(MLOG$_EMP.OLD_NEW$$, 'N', 1, -1) * MLOG$_EMP.SAL), 0)

よくわからんですね、これだけじゃ。。。説明します。

今回のテーマであるcount(sal)の項目cnt_salは、MERGE文のUPDATE句で使用さ
れています。UPDATE句では、CNT_SAL + [式1]が0の場合にSUM_SALの項目に
NULLをセットしています。
[式1]では、元表に追加/削除された行数を数えて集計しています。
(行追加:*1、行削除:* -1)

つまり、元表でNULL以外の行数が0行の場合、マテビューのSUM_SALの値にNULL
をセットする。極端な例でいうと、EMP表に10行あってそのSALの値が全てNULL
だった場合に、マテビューの値をNULLに更新している、ということになります。

count(*)もそうでしたが、高速リフレッシュでは通常の集計の値と同じにする
為に裏でいろいろと処理しているようです。

2)DBMS_MVIEW.EXPLAIN_MVIEW
以上、高速リフレッシュの制限について見てきました。高速リフレッシュには
これ以外にもいくつかの制限が存在します。

REFRESHオプションをデフォルトのFORCEに設定しているような環境の場合、実
は完全リフレッシュしか実行されていなかった、なんてことがありますので、
マテビューが高速リフレッシュ可能かどうか事前に確認しておきましょう。

DBMS_MVIEW.EXPLAIN_MVIEWを使用することで、既存のマテビュー及び作成予定
のSQL文を指定して、高速リフレッシュ可能かどうかを確認することができます。

まずは、前回の検証で使用したマテビューでDBMS_MVIEW.EXPLAIN_MVIEWを実行
してみます。

SQL> @?/rdbms/admin/utlxmv.sql

SQL> create materialized view log on emp with rowid( job, sal )
     including new values;

SQL> create materialized view mv_parttime refresh fast
     as select job, sum(sal) sum_sal from emp group by job;

SQL> exec dbms_mview.explain_mview( 'mv_parttime' );

SQL> select capability_name, possible, related_text, msgtxt
     from mv_capabilities_table where capability_name Like '%REFRESH%'
     and capability_name not Like '%PCT%';

※PCTはパーティション単位での高速リフレッシュの可否についてであり、今
  回はパーティション表ではないので割愛しています。


CAPABILITY_NAME               POS REL_TEXT  MSGTXT
----------------------------- --- --------- ------------------------------------
REFRESH_COMPLETE              Y
REFRESH_FAST                  Y
REFRESH_FAST_AFTER_INSERT     Y
REFRESH_FAST_AFTER_ONETAB_DML N   SUM_SAL   COUNT(expr)のないSUM(expr)
REFRESH_FAST_AFTER_ONETAB_DML N             選択リストにCOUNT(*)が存在しません
REFRESH_FAST_AFTER_ANY_DML    N   SCOTT.EMP mvログには順序番号がありません
REFRESH_FAST_AFTER_ANY_DML    N             REFRESH_FAST_AFTER_ONETAB_DMLを
                                            使用できない理由を参照してください

DBMS_MVIEW.EXPLAIN_MVIEWを実行することで、POSSIBLEやMSGTXT等の情報が、
MV_CAPABILITIES_TABLEというテーブルに格納されます。
POSSIBLEには指定したマテビューが高速リフレッシュ可能かどうかが、MSGTXT
には高速リフレッシュできない理由がそれぞれ入っています。
※MV_CAPABILITIES_TABLEは、utlxmv.sqlを実行することで作成されます。

possibleの値が「Y」なら高速リフレッシュ可能ということを表しています。

今回実験したマテビューは、count(*)、count(sal)列がないので、REFRESH_F
AST_AFTER_INSERT(INSERT文の後の高速リフレッシュ)が「Y」、その他の高
速リフレッシュが「N」になっています。

と、ここで気になるのが、REFRESH_FAST_AFTER_ONETAB_DMLとREFRESH_FAST_A
FTER_ANY_DMLという項目。直訳すると、それぞれ、単一テーブルへ更新した後
の高速リフレッシュ、複数テーブルへ更新した後の高速リフレッシュという意
味になります。

これらは何故別項目になっているのでしょうか。
複数テーブルに更新した後に高速リフレッシュができない、ということなので
しょうか。

と、MV_CAPABILITIES_TABLEをよくみると、「mvログには順序番号がありません」
というメッセージが出力されています。

制限をマニュアルを確認すると、

混在型のDML操作(複数の表に対するINSERT、UPDATEまたはDELETE操作の組
合せ)を実行しないことが確実でないかぎり、キーワードSEQUENCEをマテリ
アライズド・ビュー・ログ文に含めることをお薦めします。
※データウェアハウス・ガイド参照

と、わかりづらい説明がありました。
MLOGにはSEQUENCE句をつけた方がよいということのようです。ってことで、
SEQUENCE句を付けて再チャレンジ!

SQL> exec dbms_mview.refresh( 'mv_parttime' );
※MLOGを初期化しておきます。

SQL> truncate table mv_capabilities_table;

SQL> alter materialized view log on emp add sequence;

SQL> exec dbms_mview.explain_mview( 'mv_parttime' );

SQL> select capability_name, possible, related_text, msgtxt
     from mv_capabilities_table where capability_name Like '%REFRESH%'
     and capability_name not Like '%PCT%';

CAPABILITY_NAME               POS REL_TEXT   MSGTXT
----------------------------- --- --------   -------------------------
REFRESH_COMPLETE               Y
REFRESH_FAST                   Y
REFRESH_FAST_AFTER_INSERT      Y
REFRESH_FAST_AFTER_ONETAB_DML  Y
REFRESH_FAST_AFTER_ANY_DML     Y

SEQUENCE句をつけることで、先ほどのメッセージは消えました。

とこのように、DBMS_MVIEW.EXPLAIN_MVIEWを使用することで高速リフレッシュ
の制限に引っかかってないか確認することができます。高速リフレッシュを利
用する際にはこのパッケージを利用してマテビューを確認した方がよいでし
ょう。

また、SEQUENCE句をつけないと複数のテーブルの更新時に高速リフレッシュさ
れないことがありますので、MLOG作成の際は、SEQUENCE句をつけ忘れないよう
気をつけましょう。

次回は、クエリーリライトの機能について検証します。

インサイトオープンワールド In 白木屋 随時開催!? 恵比寿にて。