マテビューを完全リフレッシュ時に DELETE ではなく TRUNCATE する

exec DBMS_MVIEW.REFRESH('MVIEW_NAME', 'C', atomic_refresh => FALSE);


ってすれば、最初に DELETE ではなく TRUNCATE が走るので速くなる。
もちろん、TRUNCATE なので、リフレッシュに失敗したらデータは消えてしまうが。

他の人の書いたソースを見たら、リフレッシュ前にマテビューのテーブルに対して TRUNCATE をしていた。
知らないというのは恐ろしいことをするもんだなと思った。
そもそも、それがサポートされる行為なのか良くわからない。

今更ながら、マニュアル には次のように書かれていた。

このパラメータをFALSEに設定すると、マテリアライズド・ビューのリストは別のトランザクションでリフレッシュされます。
完全リフレッシュの一環として、切捨てが使用されると(アトミック以外のリフレッシュ)、一意索引の再作成が実行されます。INDEX REBUILDによって統計情報が自動的に計算されます。そのため、切り捨てられた表では統計情報が更新されます。


何!一意索引しかリビルドしてくれないだと!
非一意索引があるとリフレッシュが遅い+統計が失効した状態になるってことですな。
なんでそういう設計にしたのかは良くわからない。リフレッシュのオプションに非一意索引をどうこうするっていうのは無いからこれを回避するには、別のアプローチが必要となる。

案1 事前に INDEX DROPして、リフレッシュ後に CREATEする。
書いてみたが、面倒だから実際やりたくない。

案2 事前に INDEX を DISABLE しておいて、後で REBUILD する。
案1よりは楽だが、それでも面倒。

案3 PARALLEL DML にする。
Enterprise Edition でかつ リソースに余裕があるのであれば、MVリフレッシュの SELECT(PARALLEL QUERYも有効にしておけばこれも速くなる可能性あり)/INSERT の INSERT も速くなるし、
PARALLEL DMLは、DIRECT INSERT になるので、自動的にインデックスのリビルドも行われる。
PARALLEL DDLも有効にしておけば、リビルドもパラで動くからは速い!
また、COMPRESS(基本圧縮)にしておくと、インデックスリビルド時のディスクアクセス・マテビューのSELECTが速くなるし、ディスク容量も減らせる(INSERT時のCPUは食うが)。
パラレル処理については、津島博士のパフォーマンス講座 を見ると良いと思う。

話はそれるが、最速でやりたいなら、PARALLEL QUERY/DDL を有効にして DROP/CREATE AS SELECT + COMPRESS(書き込みが遅い場合)、CREATE INDEX でしょうね。

この記事へのコメント