ヘッダーをスキップ
Oracle® Databaseデータ・ウェアハウス・ガイド
11gリリース2 (11.2)
B56309-04
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

16 データ・ウェアハウスのメンテナンス

この章では、データ・ウェアハウスのロードおよびリフレッシュ方法について説明します。内容は次のとおりです。

パーティション化によるデータ・ウェアハウス・リフレッシュの改善

ETL(抽出、変換、ロード)がスケジュールに基づいて実行され、オリジナルのソース・システムに対して行われた変更が反映されます。このステップ中に、新しいクリーン・データを本番データ・ウェアハウス・スキーマに物理的に挿入し、この新しいデータがエンド・ユーザーにも利用できるように、必要に応じてその他のステップ(索引の作成、制約の妥当性チェック、データのバックアップ作成など)をすべて実行します。このデータがすべてデータ・ウェアハウスにロードされた後に、最新データが反映されるようにマテリアライズド・ビューを更新する必要があります。

データ・ウェアハウスのパーティション化方法によって、データ・ウェアハウスのロード・プロセスにおけるリフレッシュ操作の効率が決まります。実際、データ・ウェアハウスの表および索引をパーティション化する方法を選択するときには、ロード・プロセスが重要な考慮点となることがあります。

非常に大規模なデータ・ウェアハウス表(スター・スキーマのファクト表など)のパーティション化方法は、データ・ウェアハウスのロード・パラダイムをベースにする必要があります。

ほとんどのデータ・ウェアハウスには、新しいデータが定期的にロードされます。たとえば、毎晩、毎週、毎月などのペースで、データ・ウェアハウスに新しいデータが格納されます。週末または月末にロードされるデータは、通常、その週またはその月のトランザクションに対応しています。このように、非常に一般的なケースでは、データ・ウェアハウスは時間ごとにロードされます。そのため、データ・ウェアハウス表には、日付列でのパーティション化が適しています。たとえば、次のデータ・ウェアハウスの例では、新しいデータがsales表に毎月ロードされるとします。また、sales表は月別にパーティション化されているとします。表salesに新しい月(2001年1月)のデータを追加するロード手順は、次のようになります。

  1. 別に用意したsales_01_2001表に新しいデータを格納します。このデータは、データ・ウェアハウスの外部から直接sales_01_2001にロードできます。また、前にデータ・ウェアハウスで実行されたデータ変換操作の結果をロードすることも可能です。sales_01_2001の列、データ型などは、sales表と同一です。このsales_01_2001表の統計情報データを収集します。

  2. sales_01_2001に索引を作成し、制約を追加します。この場合も、sales_01_2001の索引および制約は、salesの索引および制約と同一とします。索引はパラレルで作成できます。また、NOLOGGINGおよびCOMPUTE STATISTICSオプションを使用する必要があります。次に例を示します。

    CREATE BITMAP INDEX sales_01_2001_customer_id_bix
      ON sales_01_2001(customer_id)
          TABLESPACE sales_idx NOLOGGING PARALLEL 8 COMPUTE STATISTICS;
    

    sales表に存在するすべての制約が、sales_01_2001表に適用される必要があります。これには参照整合性制約も含まれます。典型的な制約の例としては、次のものがあります。

    ALTER TABLE sales_01_2001 ADD CONSTRAINT sales_customer_id
          REFERENCES customer(customer_id) ENABLE NOVALIDATE;
    

    パーティション表salesにグローバル索引構造により強制適用される主キーまたは一意キーがある場合は、索引構造を作成せずに、次のようにしてsales_pk_jan01の制約が有効になるようにしてください。

    ALTER TABLE sales_01_2001 ADD CONSTRAINT sales_pk_jan01
    PRIMARY KEY (sales_transaction_id) DISABLE VALIDATE;
    

    ENABLE句で制約を作成すると、パーティション表のローカル索引構造と一致しない一意索引が作成されます。非パーティション表に、パーティション表の既存のグローバル索引と交換される索引構造を作成しないでください。EXCHANGEコマンドが失敗します。

  3. sales_01_2001表をsales表に追加します。

    この新しいデータをsales表に追加するには、2つの操作が必要です。まず、sales表に新しいパーティションを追加します。これには、ALTER TABLE ... ADD PARTITION文を使用します。これによって、sales表に空のパーティションが追加されます。

    ALTER TABLE sales ADD PARTITION sales_01_2001 
    VALUES LESS THAN (TO_DATE('01-FEB-2001', 'DD-MON-YYYY'));
    

    この後、EXCHANGE PARTITION操作によって、新しく作成した表をこのパーティションに追加できます。この操作によって、新しい空のパーティションが、新しくロードされた表と交換されます。

    ALTER TABLE sales EXCHANGE PARTITION sales_01_2001 WITH TABLE sales_01_2001 
    INCLUDING INDEXES WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
      
    

    EXCHANGE操作は、sales_01_2001表にすでにあった索引および制約を保存します。一意制約(sales_transaction_idの一意制約など)の場合は、前述のようにUPDATE GLOBAL INDEXES句を使用できます。これにより、グローバル索引構造はパーティション・メンテナンス操作の一部として自動的にメンテナンスされ、プロセス全体でアクセス可能な状態に保たれます。外部キー制約のみの場合は、EXCHANGE操作はすぐに処理を終了します。

このパーティション化テクニックには、重要な利点があります。第1に、新しいデータのロードに使用するリソースが最小限に抑えられます。新しいデータは、完全に別々の表にロードされるため、索引および制約の処理は、その新しいパーティションのみに適用されます。sales表が50GBで、12のパーティションを持つとすると、新しい月のデータ・サイズは約4GBになります。索引を作成する必要があるのは新しい月のデータのみです。残りの46GBのデータに関する索引は、まったく変更する必要はありません。このパーティション化方法では、ロード処理時間は、sales表全体のサイズではなく、新しいデータの量に比例します。

第2に、同時問合せへの影響を最小限に抑えて、新しいデータをロードできます。データのロードに関連する操作は、すべて別のsales_01_2001表に対して発生しています。したがって、sales表の既存のデータや索引はデータのリフレッシュ処理中にはまったく影響を受けません。このリフレッシュ処理の間、sales表およびその索引に、処理が加えられないようにできます。

第3に、グローバル索引が存在する場合は、交換コマンドの一部として段階的にメンテナンスされます。このメンテナンスは、既存のグローバル索引構造の可用性には影響しません。

EXCHANGE操作は、公開機能と見ることができます。データ・ウェアハウスの管理者がsales_01_2001表をsales表に交換するまで、エンド・ユーザーは新しいデータを参照できません。EXCHANGEが実行されると、その直後に、sales表にアクセスするすべてのエンド・ユーザー問合せからsales_01_2001データが参照できるようになります。

パーティション化は、新しいデータの追加のみでなく、データの削除やアーカイブにも有効です。多くのデータ・ウェアハウスがデータのローリング・ウィンドウを保持しています。たとえば、データ・ウェアハウスには最近36か月のsalesデータが格納されているとします。sales表に新しいパーティションを追加できるのと同じように(前述参照)、古いパーティションも即座に(かつ他に影響を及ぼさずに)sales表から削除できます。パーティションの追加には2つの効果(リソース使用の削減およびエンド・ユーザーへの影響の最小化)がありますが、これはパーティションの削除にも当てはまります。

パーティション表からデータを削除しても、必ずしも古いデータがデータベースから物理的に削除されるわけではありません。パーティション表からデータを削除するには、他に次の2つの方法があります。1つ目は、古いデータが含まれているパーティションを削除して割り当てられている領域を解放することで、データベースからすべてのデータを物理的に削除する方法です。

ALTER TABLE sales DROP PARTITION sales_01_1998;

2つ目は、古いパーティションを、同じ構造を持つ空の表と交換する方法です。この空の表は、ロード処理のステップ1と2で説明したのと同じ手順で作成します。新しい空の表スタブの名前をsales_archive_01_1998とすると、次のSQL文でパーティションsales_01_1998が「空に」なります。

ALTER TABLE sales EXCHANGE PARTITION sales_01_1998 
WITH TABLE sales_archive_01_1998 INCLUDING INDEXES WITHOUT VALIDATION 
UPDATE GLOBAL INDEXES;

古いデータは、交換された非パーティション表sales_archive_01_1998としてまだ存在していることに注意してください。

すべてのパーティションを別々の表領域に格納するという方法でパーティション表が設定されていた場合は、実際のデータ(表領域)を削除する前に、Oracle Databaseのトランスポータブル表領域フレームワークを使用して、この表をアーカイブ(または転送)できます。トランスポータブル表領域の詳細は、「トランスポータブル表領域を使用した転送」を参照してください。

場合によっては、古いデータをすぐに削除するのではなく、パーティション表の一部として保持することが必要な場合があります。このデータはもう重要ではありませんが、この古い読取り専用のデータにアクセスする問合せがまだ存在する可能性があります。古いデータの使用領域を最小化するには、Oracleのデータ圧縮を使用できます。1つ以上の圧縮パーティションがすでにパーティション表の一部に含まれていることも想定されます。


関連項目:


リフレッシュの使用例

典型的な使用例では、古いデータを圧縮するのみでなく、いくつかの古いパーティションを将来のバックアップの最小処理単位にマージすることが必要な場合があります。バックアップ(パーティション)の最小処理単位がどの四半期についても四半期ベースであり、最も古い月と最新の月の差が36か月より多いものとします。この場合、sales_01_1998sales_02_1998およびsales_03_1998を新しい圧縮パーティションsales_q1_1998に圧縮およびマージすることになります。

  1. 別の表領域に新しいマージ・パーティションをパラレルに作成します。パーティションは、次のMERGE操作の一部として圧縮されます。

    ALTER TABLE sales MERGE PARTITIONS sales_01_1998, sales_02_1998, sales_03_1998
     INTO PARTITION sales_q1_1998 TABLESPACE archive_q1_1998 
    COMPRESS UPDATE GLOBAL INDEXES PARALLEL 4;
    
  2. パーティションのMERGE操作により、新しいマージ・パーティションに対するローカル索引は無効になります。したがって、再作成する必要があります。

    ALTER TABLE sales MODIFY PARTITION sales_q1_1998 
    REBUILD UNUSABLE LOCAL INDEXES;
    

かわりに、パーティション表の外部に新しい圧縮表を作成して、これと交換する方法も選択できます。どちらの方法でも、パフォーマンスと一時領域の使用量は同程度です。

  1. マージされた新しい情報を格納する中間的な表を作成します。次の文は、デフォルトで、元の表からNOT NULL制約をすべて継承します。

    CREATE TABLE sales_q1_1998_out TABLESPACE archive_q1_1998 
    NOLOGGING COMPRESS PARALLEL 4 AS SELECT * FROM sales
    WHERE time_id >=  TO_DATE('01-JAN-1998','dd-mon-yyyy')
      AND time_id < TO_DATE('01-APR-1998','dd-mon-yyyy');
    
  2. 既存の表salesの他に、表sales_q1_1998_outに対して等価な索引構造を作成します。

  3. 既存の表salesを、新しい圧縮表sales_q1_1998_outと交換するために準備します。交換される表には、実際には3つのパーティションにまたがるデータが含まれているため、参照中のレンジ境界を持つ、一致するパーティションを1つ作成する必要があります。既存のパーティションを2つ削除するだけで済みます。低い方のパーティションsales_01_1998sales_02_1998を削除する必要があることに注意してください。レンジ・パーティションの下限は、常に前のパーティションの上限(上限を含まない)によって定義されます。

    ALTER TABLE sales DROP PARTITION sales_01_1998;
    ALTER TABLE sales DROP PARTITION sales_02_1998;
     
    
  4. これで、表sales_q1_1998_outをパーティションsales_03_1998と交換できます。パーティションの名前から想定されるものとは異なり、この境界は1998年の第1四半期をカバーします。

    ALTER TABLE sales EXCHANGE PARTITION sales_03_1998 
    WITH TABLE sales_q1_1998_out INCLUDING INDEXES WITHOUT VALIDATION 
    UPDATE GLOBAL INDEXES;
    

どちらの方法も、多少異なるビジネス・シナリオに適用されます。MERGE PARTITIONを使用する方法では、影響を受けるパーティションのローカル索引構造は無効になりますが、データは常時アクセス可能なまま保たれます。影響を受けるパーティションに対して、使用できない索引構造の1つを介してアクセスしようとすると、エラーが発生します。使用が制限される時間は、ローカル・ビットマップ索引構造を再作成するための時間とほぼ同程度になります。ほとんどの場合、これは無視できます。パーティション表のこの部分はそれほど頻繁にアクセスされないためです。

ただし、CTAS方法では索引構造が使用できない時間はゼロに近く短縮されますが、パーティション表にすべてのデータが揃わない特定の時間枠があります。これは、2つのパーティションを削除したためです。使用が制限される時間は、表を交換するための時間とほぼ同程度になります。グローバル索引の有無およびその数によって、この時間枠は変わります。既存のグローバル索引がない場合、この時間枠はほんの数秒です。

これらの例は、データ・ウェアハウスのローリング・ウィンドウのロードの使用例を単純化したものです。実際のデータ・ウェアハウスのリフレッシュ特性は、さらに複雑です。ただし、このローリング・ウィンドウを使用すると、リフレッシュ特性がさらに複雑になっても、十分な効果を得ることができます。

パーティション表に単一または複数の圧縮パーティションを初めて追加するときは、その前にローカル・ビットマップ索引をすべて削除するか使用不可にマークする必要があることに注意してください。最初に圧縮パーティションを追加した後は、圧縮パーティションに関するその後のどの操作においても追加の処置は必要ありません。これは、どのような方法で圧縮表に圧縮パーティションが追加されたかには関係ありません。


関連項目:

  • パーティション化と表の圧縮については、『Oracle Database VLDBおよびパーティショニング・ガイド』を参照してください。

  • パーティション化と表の圧縮の詳細は、『Oracle Database管理者ガイド』を参照してください。


データ・ウェアハウスのリフレッシュにパーティション化を使用する使用例

ここでは、リフレッシュにパーティション化を使用する一般的な例を2つ紹介します。

リフレッシュ使用例1

データは毎日ロードされます。ただし、データ・ウェアハウスには2年分のデータを格納するため、1日単位のパーティションは適切ではありません。

ソリューションは、週別または月別(適切な方)にパーティション化することです。INSERTを使用して、新しいデータを既存のパーティションに追加します。INSERT操作が影響するパーティションは1つのみなので、前述の利点はそのまま残ります。INSERT操作は、パーティションが表の一部である場合に行うことができます。単一パーティションへのINSERTはパラレル化できます。

INSERT /*+ APPEND*/ INTO sales PARTITION (sales_01_2001) 
SELECT * FROM new_sales;

このsalesパーティションの索引もパラレルでメンテナンスされます。このメソッドのかわりにEXCHANGE操作を使用することもできます。そのためには、sales表のsales_01_2001パーティションを交換し、INSERT操作を使用します。この方法を使用するのは、索引をメンテナンスするよりも、削除して再作成する方が効率的な場合です。

リフレッシュ使用例2

新しいデータは、主に最近の日、週、月などのものから構成されますが、以前の期間のデータも含まれます。

ソリューション1

パラレルSQL操作(CREATE TABLE ... AS SELECTなど)を使用して、新しいデータを以前の期間のデータから分離します。日付が古いデータは、他のテクニックを使用して別に処理します。

新しいデータは、必ず時間ベースであるとは限りません。データ・ウェアハウスがビジネス・ニーズに基づいて複数の業務系システムから新規データを受け取るようにすることもできます。たとえば、直接チャネルからの売上データが、間接チャネルからのデータとは別にデータ・ウェアハウスに格納されることもあります。また、業務上の理由から、直接データと間接データを別のパーティションに保存することも適しています。

ソリューション2

Oracleでは、コンポジット・レンジ-リスト・パーティション化をサポートしています。sales表の主要なパーティション化方法は、例に示すようにtime_idに基づいたレンジ・パーティション化にできます。ただし、サブパーティション化は、チャネル属性に基づいたリストです。これで各サブパーティションを互いに(それぞれ別個のチャネルごとに)独立にロードして、前述のローリング・ウィンドウ操作で追加できます。パーティション化方式は、最も最適化された方法でビジネス・ニーズを処理します。

リフレッシュ中のDML操作の最適化

DMLパフォーマンスは、次の方法で最適化できます。

効率的なMERGE操作の実装

ソース・システムから抽出したデータは、データ・ウェアハウスに挿入する必要のある新しいレコードの単なるリストではありません。この新しいデータセットは、新しいレコードと変更レコードの組合せで構成されます。たとえば、OLTPシステムから抽出したデータのほとんどが新しい売上トランザクションによるものだとします。これらのレコードは、ウェアハウスのsales表に挿入されますが、その中には、商品の返品や、最初にデータ・ウェアハウスにロードしたときに不備があったトランザクションの修正など、以前のトランザクションに対する変更を反映しているものがある場合があります。このようなレコードについては、sales表の更新が必要です。

new_sales表があり、この表にsales表に適用される挿入項目と更新項目の両方が格納されている例を考えてみます。データ・ウェアハウスのロード・プロセス全体を設計するときに、次のような処理方法で、このnew_sales表にレコードを格納することにします。

  • new_sales表のレコードの任意のsales_transaction_idsales表にすでに存在する場合、new_sales表からsales_dollar_amountおよびsales_quantity_soldの値をsales表の既存の行に追加することで、sales表を更新します。

  • それ以外の場合は、new_sales表から新しいレコード全体をsales表に挿入します。

このUPDATE-ELSE-INSERT操作は、通常はマージと呼ばれます。マージは、1つのSQL文で実行できます。

例16-1 MERGE操作

MERGE INTO sales s USING new_sales n
ON (s.sales_transaction_id = n.sales_transaction_id)
WHEN MATCHED THEN
UPDATE SET s.sales_quantity_sold = s.sales_quantity_sold + n.sales_quantity_sold,
 s.sales_dollar_amount = s.sales_dollar_amount + n.sales_dollar_amount
WHEN NOT MATCHED THEN INSERT (sales_transaction_id, sales_quantity_sold, 
sales_dollar_amount)
VALUES (n.sales_transcation_id, n.sales_quantity_sold, n.sales_dollar_amount);

ターゲット表に対する無条件のUPDATE ELSE INSERT機能でMERGE文を使用することに加えて、次のことも可能です。

  • UPDATEのみ、またはINSERTのみの文を実行する。

  • 追加のWHERE条件をMERGE文のUPDATEまたはINSERT部分に適用する。

  • 特定の条件がTRUEの場合、UPDATE操作で行を削除する。

例16-2 INSERT句の省略

一部のデータ・ウェアハウス・アプリケーションでは、新しい行を履歴情報に追加することはできず、更新のみが可能なものがあります。また、更新ではなく新しい情報の挿入のみが必要な場合があります。次の文は、UPDATEのみ使用してINSERT機能のみを実行する例です。

MERGE USING Product_Changes S     -- Source/Delta table
INTO Products D1                  -- Destination table 1
ON (D1.PROD_ID = S.PROD_ID)       -- Search/Join condition
WHEN MATCHED THEN UPDATE          -- update if join
SET D1.PROD_STATUS = S.PROD_NEW_STATUS

例16-3 UPDATE句の省略

次の文は、UPDATEを省略する例です。

MERGE USING New_Product S           -- Source/Delta table
INTO Products D2                    -- Destination table 2
ON (D2.PROD_ID = S.PROD_ID)         -- Search/Join condition
WHEN NOT MATCHED THEN               -- insert if no join
INSERT (PROD_ID, PROD_STATUS) VALUES (S.PROD_ID, S.PROD_NEW_STATUS)

INSERT句を省略した場合は、ソース表とターゲット表に対して通常の結合が実行されます。UPDATE句を省略した場合は、ソース表とターゲット表に対してアンチ結合が実行されます。これによって、ソース表とターゲット表がより効率的に結合されます。

例16-4 UPDATE句のスキップ

特定の行を表にマージする際に、UPDATE操作をスキップしなければならない場合があります。この場合、MERGEUPDATE句にオプションのWHERE句を使用できます。その結果、UPDATE操作は、指定した条件がTRUEの場合にのみ実行されるようになります。次の文は、UPDATE操作をスキップする例を示しています。

MERGE 
USING Product_Changes S                      -- Source/Delta table 
INTO Products P                              -- Destination table 1 
ON (P.PROD_ID = S.PROD_ID)                   -- Search/Join condition 
WHEN MATCHED THEN 
UPDATE                                       -- update if join 
SET P.PROD_LIST_PRICE = S.PROD_NEW_PRICE 
WHERE P.PROD_STATUS <> "OBSOLETE"            -- Conditional UPDATE

次に、条件P.PROD_STATUS <> "OBSOLETE"がTRUEではない場合にUPDATE操作がどのようにスキップされるかを示します。条件の述語は、ターゲット表とソース表の両方を指すことができます。

例16-5 MERGE文の条件付き挿入

特定の行を表にマージする際に、INSERT操作をスキップしなければならない場合があります。この場合、MERGEINSERT句にオプションのWHERE句を追加します。その結果、INSERT操作は、指定した条件がTRUEの場合にのみ実行されるようになります。次に例を示します。

MERGE USING Product_Changes S                      -- Source/Delta table
INTO Products P                                    -- Destination table 1
ON (P.PROD_ID = S.PROD_ID)                         -- Search/Join condition
WHEN MATCHED THEN UPDATE                           -- update if join
SET P.PROD_LIST_PRICE = S.PROD_NEW_PRICE
WHERE P.PROD_STATUS <> "OBSOLETE"                  -- Conditional
WHEN NOT MATCHED THEN
INSERT (PROD_ID, PROD_STATUS, PROD_LIST_PRICE)     -- insert if not join
VALUES (S.PROD_ID, S.PROD_NEW_STATUS, S.PROD_NEW_PRICE)
WHERE S.PROD_STATUS <> "OBSOLETE";                 -- Conditional INSERT

この例は、条件S.PROD_STATUS <> "OBSOLETE"がTRUEではない場合にINSERT操作がスキップされ、条件がTRUEのときにのみINSERTが実行されることを示します。条件の述語は、ソース表のみを指すことができます。条件の述語は、ソース表のみを指すことができます。

例16-6 MERGE文でのDELETE句の使用

表を移入または更新する際に、表をクレンジングする場合があります。この場合、次の例のように、MERGE文でDELETE句を使用できます。

MERGE USING Product_Changes S
INTO Products D ON (D.PROD_ID = S.PROD_ID)
WHEN MATCHED THEN
UPDATE SET D.PROD_LIST_PRICE =S.PROD_NEW_PRICE, D.PROD_STATUS = S.PROD_NEWSTATUS
DELETE WHERE (D.PROD_STATUS = "OBSOLETE")
WHEN NOT MATCHED THEN
INSERT (PROD_ID, PROD_LIST_PRICE, PROD_STATUS)
VALUES (S.PROD_ID, S.PROD_NEW_PRICE, S.PROD_NEW_STATUS);

このように、行がproductsで更新される際に、削除条件D.PROD_STATUS = "OBSOLETE"がチェックされ、条件がTRUEであれば行が削除されます。

DELETE操作は、完全なDELETE文の削除とは異なります。MERGE先の行のみが削除されます。DELETEの影響を受ける行のみが、このMERGE文で更新される行です。したがって、目的の表で指定した行が削除条件に合致しても、ON句の条件の下で結合を実行しない場合は削除されません。

例16-7 MERGE文の無条件の挿入

ソースのすべての行を表に挿入する場合があります。この場合、ソース表とターゲット表の結合を避けることができます。1=0など、常にFALSEになる特殊な一定の結合条件を指定することで、このようなMERGE文は最適化され、結合条件は無効になります。

MERGE USING New_Product S       -- Source/Delta table 
INTO Products P                 -- Destination table 1 
ON (1 = 0)                      -- Search/Join condition 
WHEN NOT MATCHED THEN           -- insert if no join 
INSERT (PROD_ID, PROD_STATUS) VALUES (S.PROD_ID, S.PROD_NEW_STATUS)

参照整合性の保持

データ・ウェアハウス環境によっては、参照整合性を保証するために新しいデータを表に挿入する必要がある場合もあります。たとえば、キャッシュ・レジスタから直接データを取り出す業務系システムからsalesを導出するデータ・ウェアハウスがあるとします。salesは毎晩リフレッシュされます。ただし、productディメンション表のデータは別の業務系システムから導出されます。productディメンション表の変更には比較的時間がかかるため、この表は週に1回しかリフレッシュされないことがあります。新製品が月曜日に導入されたとすると、その製品のproduct_idがデータ・ウェアハウスのproduct表に挿入される前に、データ・ウェアハウスのsalesデータ内にproduct_idが表示される可能性があります。

この新製品の売上トランザクションは有効ですが、その売上データは、productディメンション表とsalesファクト表間の参照整合性制約を満たしません。この場合、新しい売上トランザクションを禁止するより、sales表にその売上トランザクションを挿入する方を選ぶのが普通です。ただし、sales表とproduct表間の参照整合性関係もメンテナンスする必要があります。これは、新しい行を不明な製品のプレースホルダとしてproduct表に挿入することによって可能になります。

前述の例のように、sales表への新しいデータは別のnew_sales表に格納されるとします。パラレル化が可能な単一のINSERT文で、product表が新製品を反映するように変更できます。

INSERT INTO product
  (SELECT sales_product_id, 'Unknown Product Name', NULL, NULL ...
   FROM new_sales WHERE sales_product_id NOT IN
  (SELECT product_id FROM product));

データの削除

データ・ウェアハウスから大量のデータを削除する必要がある場合もあります。前述のローリング・ウィンドウでは、古いデータをデータ・ウェアハウスからロールアウトして新しいデータの領域を確保するという、非常に一般的な例を取り上げました。

ただし、それ以外の場合でも、データをデータ・ウェアハウスから削除する必要がある場合があります。たとえば、ある小売会社が、以前にXYZ Software社の製品を販売し、その後XYZ Softwareが廃業したとします。データ・ウェアハウスを業務で利用しているユーザーが、XYZ Software社に関するデータはもう必要ないと判断し、このデータを削除することになりました。

大量のデータを削除する方法の1つに、パラレル削除による方法があります。例を次に示します。

DELETE FROM sales WHERE sales_product_id IN (SELECT product_id 
   FROM product WHERE product_category = 'XYZ Software');

このSQL文では、パーティションごとに1つのパラレル処理が起動されます。この方法のメリットは、シリアルDELETE文よりはるかに効率的で、sales表のデータは移動する必要がないことです。ただし、いくつかのデメリットもあります。行の大部分を削除する場合、DELETE文は既存のパーティションに多数の行スロットを残します。その後、新しいデータがローリング・ウィンドウ・テクニックによってロードされても(またはダイレクト・パス・インサートまたはダイレクト・パス・ロードによってロードされても)、この記憶領域は再使用されません。また、DELETE文はパラレル化できますが、それより効率的な方法もあります。別の方法としては、XYZ Software社以外の製品カテゴリのデータをすべて維持したまま、sales表全体を再作成する方法があります。

CREATE TABLE sales2 AS SELECT * FROM sales, product
WHERE sales.sales_product_id = product.product_id 
AND product_category <> 'XYZ Software'
NOLOGGING PARALLEL (DEGREE 8)
#PARTITION ... ; #create indexes, constraints, and so on
DROP TABLE SALES;
RENAME SALES2 TO SALES;

この方法は、パラレルDELETEより効率的です。ただし、sales表を2回インスタンス化することになるため、この方法もディスク領域の使用量の面ではコストが高くなります。

ディスク領域の使用量が少ない別の方法として、sales表を一度に1パーティションずつ再作成する方法があります。

CREATE TABLE sales_temp AS SELECT * FROM sales WHERE 1=0;
INSERT INTO sales_temp
SELECT * FROM sales PARTITION (sales_99jan), product
WHERE sales.sales_product_id = product.product_id
AND product_category <> 'XYZ Software';
<create appropriate indexes and constraints on sales_temp>
ALTER TABLE sales EXCHANGE PARTITION sales_99jan WITH TABLE sales_temp;

sales表の各パーティションに対して、このプロセスを繰り返します。

マテリアライズド・ビューのリフレッシュ

マテリアライズド・ビューを作成する場合、リフレッシュをON DEMANDで行うか、ON COMMITで行うかを指定できます。ON COMMITの場合は、トランザクションがコミットされるたびに、マテリアライズド・ビューが変更されます。このため、マテリアライズド・ビューに常に最新データが含まれていることが保証されます。または、ON DEMANDを指定すると、マテリアライズド・ビューのリフレッシュが発生する時期を制御できます。この場合、マテリアライズド・ビューをリフレッシュするには、DBMS_MVIEWパッケージ内のプロシージャの1つをコールする必要があります。

DBMS_MVIEWパッケージでは、次の3通りのリフレッシュ操作が利用できます。

リフレッシュ操作の実行には、索引再構築のための一時領域が必要で、リフレッシュ操作そのものを実行するために追加の領域が必要な場合もあります。サイトによっては、マテリアライズド・ビューを同時にすべてリフレッシュすることが適切ではない場合もあります。ベースとなるディテール・データが更新されると、このデータを使用するすべてのマテリアライズド・ビューが失効します。したがって、マテリアライズド・ビューのリフレッシュを遅延させる場合は、選択したリライトの整合性レベルを信頼して、失効したマテリアライズド・ビューがクエリー・リライトに使用できるかどうかを判断するか、または、ALTER SYSTEM SET QUERY_REWRITE_ENABLED = FALSE文でクエリー・リライトを一時的に使用禁止にできます。マテリアライズド・ビューのリフレッシュ後に、ALTER SYSTEM SET QUERY_REWRITE_ENABLEDTRUEを指定すると、現行のデータベース・インスタンスにあるすべてのセッションに対して、クエリー・リライトをデフォルトの状態である使用可能に戻すことができます。マテリアライズド・ビューをリフレッシュすると、そのすべての索引が自動的に更新されます。完全リフレッシュの場合は、リフレッシュ中にすべての索引を再作成できるように、一時ソート領域が必要です。これは、完全リフレッシュでは、新しいデータ・ボリューム全体が挿入される前に表が切り捨てられるか、削除されるためです。索引再作成のための一時領域が不足している場合は、リフレッシュ操作の前に明示的に各索引を削除するか、UNUSABLEマークを付ける必要があります。

マテリアライズド・ビューで参照される表に対する挿入、更新または削除操作が、そのマテリアライズド・ビューのリフレッシュと同時に実行されると予想され、そのマテリアライズド・ビューに結合と集計が含まれている場合は、ON DEMAND高速リフレッシュではなくON COMMIT高速リフレッシュを使用することをお薦めします。


関連項目:

キューブ・マテリアライズド・ビューのリフレッシュの詳細は、『Oracle OLAPユーザーズ・ガイド』を参照してください。

完全リフレッシュ

完全リフレッシュは、マテリアライズド・ビューを最初にBUILD IMMEDIATEで定義した場合に実行されます。ただし、そのマテリアライズド・ビューが事前作成表を参照する場合は除きます。BUILD DEFERREDを使用するマテリアライズド・ビューの場合は、初めて使用する前に完全リフレッシュを実行する必要があります。完全リフレッシュは、どのマテリアライズド・ビューの場合も必要に応じて要求できます。このリフレッシュでは、ディテール表が読み込まれ、マテリアライズド・ビューの結果が計算されます。これは、読み込まれて処理されるデータが大量の場合には、時間がかかる処理です。そのため、完全リフレッシュを要求する前に、必ずその処理時間を考慮してください。

また、すでに作成済のマテリアライズド・ビューが次の項で説明する高速リフレッシュの条件を満たしていないために、完全リフレッシュしか使用できない場合もあります。

高速リフレッシュ

ほとんどのデータ・ウェアハウスでは、そのディテール・データが定期的に増分更新されます。「マテリアライズド・ビューのスキーマ・デザイン」で説明したように、SQL*Loaderまたはバルク・ロード・ユーティリティを使用して、ディテール・データの増分ロードを実行できます。通常、マテリアライズド・ビューの高速リフレッシュは効率的です。これは、すべてのマテリアライズド・ビューを再計算するのではなく、変更分のみが既存のデータに適用されるためです。このように、変更のみを処理するため、リフレッシュ時間を大幅に削減できます。

パーティション・チェンジ・トラッキング(PCT)リフレッシュ

ディテール表に対するパーティション・メンテナンス操作がある場合、高速リフレッシュにはこの方法しか使用できません。マテリアライズド・ビューに対するPCTベースのリフレッシュは、「パーティション・チェンジ・トラッキング」で説明しているすべての条件を満たした場合にのみ有効です。

ディテール表に対するパーティション・メンテナンス操作がない場合、DBMS_MVIEWパッケージのプロシージャでリフレッシュのFASTメソッド(method => 'F')を要求すると、PCTリフレッシュが選択される前に、ログベースのルールの高速リフレッシュを試行するヒューリスティックなルールが使用されます。同様に、FORCEメソッド(method => '?')を要求すると、ログベースの高速リフレッシュ、PCTリフレッシュ、完全リフレッシュの試行順序に基づいてリフレッシュ方法が選択されます。または、PCTメソッド(method => 'P')を要求することもできます。Oracleは、すべてのPCT要件が満たされている場合はPCTメソッドを使用します。

「マテリアライズド・ビューのパーティション化によるメリット」で説明されている条件を満たしており、PCTリフレッシュ・プロセスを効率的に実行できる場合は、マテリアライズド・ビューに対してTRUNCATE PARTITIONを使用できます。

ON COMMITリフレッシュ

ON COMMITメソッドを使用すると、マテリアライズド・ビューを自動的にリフレッシュできます。したがって、マテリアライズド・ビューが定義されている表の更新トランザクションがコミットされるたびに、その変更内容がマテリアライズド・ビューに自動的に反映されます。このアプローチを使用するメリットは、マテリアライズド・ビューのリフレッシュに注意する必要がないことです。唯一のデメリットは、余分な処理が必要なため、コミット完了までの所要時間が少し長くなることです。ただし、データ・ウェアハウスでは、同時プロセスで同じ表の更新が試みられることはまずないため、これは問題ではありません。

DBMS_MVIEWパッケージによる手動リフレッシュ

マテリアライズド・ビューのON DEMANDリフレッシュを行う場合は、次の表のように4つのリフレッシュ方法から1つ指定できます。デフォルト・オプションは、マテリアライズド・ビューの作成時に定義できます。表16-1にリフレッシュ・オプションを示します。

表16-1 ON DEMANDリフレッシュ方法

リフレッシュ・オプション パラメータ 説明

COMPLETE

C

マテリアライズド・ビューの定義問合せを再計算することでリフレッシュします。

FAST

F

マテリアライズド・ビューへの変更を増分的に適用することでリフレッシュします。

ローカル・マテリアライズド・ビューの場合は、オプティマイザが最も効率的と判断したリフレッシュ方法が選択されます。考えられるリフレッシュ方法は、ログベースのFASTFAST_PCTです。

FAST_PCT

P

ディテール表で変更されたパーティションの影響を受けるマテリアライズド・ビューの行を再計算することでリフレッシュします。

FORCE

?

高速リフレッシュを試みます。それができない場合は、完全リフレッシュを行います。

ローカル・マテリアライズド・ビューの場合は、オプティマイザが最も効率的と判断したリフレッシュ方法が選択されます。考えられるリフレッシュ方法は、ログベースのFASTFAST_PCTおよびCOMPLETEです。


ON DEMANDリフレッシュを実行するために、DBMS_MVIEWパッケージの3つのリフレッシュ・プロシージャを使用できます。それぞれに、一連の固有のパラメータがあります。


関連項目:

  • DBMS_MVIEWパッケージの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

  • レプリケーション環境で使用する方法は、『Oracle Databaseアドバンスト・レプリケーション』を参照してください。


REFRESHを使用した特定のマテリアライズド・ビューのリフレッシュ

DBMS_MVIEW.REFRESHプロシージャを使用して、1つ以上のマテリアライズド・ビューをリフレッシュできます。一部のパラメータはレプリケーションにのみ使用されるため、ここでは説明しません。このプロシージャを使用するために必要なパラメータは次のとおりです。

  • カンマで区切られた、リフレッシュ対象のマテリアライズド・ビューのリスト

  • リフレッシュ方法: F-Fast、P-Fast_PCT、?-Force、C-Complete

  • 使用するロールバック・セグメント

  • エラー発生後のリフレッシュ(TRUEまたはFALSE)

    ブール・パラメータ。TRUEに設定すると、number_of_failures出力パラメータは失敗したリフレッシュの数に設定され、通常のエラー・メッセージによって失敗の発生が示されます。インスタンスに関するアラート・ログに、リフレッシュ・エラーの詳細が示されます。デフォルト値のFALSEに設定すると、最初にエラーが発生したときにリフレッシュが停止し、リスト内の残りのマテリアライズド・ビューはリフレッシュされません。

  • 次の4つのパラメータは、レプリケーション・プロセスで使用されます。ウェアハウスのリフレッシュの場合は、FALSE, 0,0,0に設定してください。

  • アトミック・リフレッシュ(TRUEまたはFALSE)

    TRUEに設定すると、すべてのリフレッシュが1トランザクションで行われます。FALSEに設定すると、指定したマテリアライズド・ビューのリフレッシュがそれぞれ別のトランザクションで行われます。FALSEに設定すると、パラレルDMLによってリフレッシュが最適化され、マテリアライズド・ビューのDDLが切り捨てられます。マテリアライズド・ビューをアトミック・モードでリフレッシュする際、リライト整合性モードがstale_toleratedに設定されている場合にクエリー・リライトを使用できます。リフレッシュがネステッド・ビューで実行される場合は、アトミック・リフレッシュは保証されません。

たとえば、マテリアライズド・ビューcal_month_sales_mvに高速リフレッシュを行うには、DBMS_MVIEWパッケージを次のようにコールします。

DBMS_MVIEW.REFRESH('CAL_MONTH_SALES_MV', 'F', '', TRUE, FALSE, 0,0,0, FALSE);

複数のマテリアライズド・ビューを同時にリフレッシュすることが可能です。また、その際、すべてに同じリフレッシュ方法を使用する必要はありません。それぞれに異なるリフレッシュ方法を適用するには、マテリアライズド・ビューのリスト順に複数のメソッド・コードを指定します(カンマなし)。たとえば、次のように指定すると、cal_month_sales_mvは完全リフレッシュされ、fweek_pscat_sales_mvは高速リフレッシュされます。

DBMS_MVIEW.REFRESH('CAL_MONTH_SALES_MV, FWEEK_PSCAT_SALES_MV', 'CF', '', 
  TRUE, FALSE, 0,0,0, FALSE);

リフレッシュ方法を指定しなければ、マテリアライズド・ビューの定義で指定したデフォルトのリフレッシュ方法が使用されます。

REFRESH_ALL_MVIEWSを使用したすべてのマテリアライズド・ビューのリフレッシュ

リフレッシュするマテリアライズド・ビューを指定する場合、プロシージャDBMS_MVIEW.REFRESH_ALL_MVIEWSを使用する方法もあります。このプロシージャでは、すべてのマテリアライズド・ビューがリフレッシュされます。リフレッシュに失敗したマテリアライズド・ビューがあると、その数がレポートされます。

このプロシージャのパラメータは次のとおりです。

  • 失敗数(OUT変数)

  • リフレッシュ方法: F-Fast、P-Fast_PCT、?-Force、C-Complete

  • エラー発生後のリフレッシュ(TRUEまたはFALSE)

    ブール・パラメータ。TRUEに設定すると、number_of_failures出力パラメータは失敗したリフレッシュの数に設定され、通常のエラー・メッセージによって失敗の発生が示されます。インスタンスに関するアラート・ログに、リフレッシュ・エラーの詳細が示されます。デフォルト値のFALSEに設定すると、最初にエラーが発生したときにリフレッシュが停止し、リスト内の残りのマテリアライズド・ビューはリフレッシュされません。

  • アトミック・リフレッシュ(TRUEまたはFALSE)

    TRUEに設定すると、すべてのリフレッシュが1トランザクションで行われます。FALSEに設定されると、各マテリアライズド・ビューは別々のトランザクションで非アトミックにリフレッシュされます。FALSEに設定すると、パラレルDMLによってリフレッシュが最適化され、マテリアライズド・ビューのDDLが切り捨てられます。マテリアライズド・ビューをアトミック・モードでリフレッシュする際、リライト整合性モードがstale_toleratedに設定されている場合にクエリー・リライトを使用できます。リフレッシュがネステッド・ビューで実行される場合は、アトミック・リフレッシュは保証されません。

次に、すべてのマテリアライズド・ビューをリフレッシュする例を示します。

DBMS_MVIEW.REFRESH_ALL_MVIEWS(failures,'C','', TRUE, FALSE);

REFRESH_DEPENDENTを使用した依存マテリアライズド・ビューのリフレッシュ

3番目のプロシージャDBMS_MVIEW.REFRESH_DEPENDENTでは、特定の表または表のリストに依存するマテリアライズド・ビューのみがリフレッシュされます。たとえば、変更がorders表には反映されるが、customer payments表には反映されないとします。orders表を参照するマテリアライズド・ビューのみをリフレッシュするには、REFRESH_DEPENDENTプロシージャをコールします。

このプロシージャのパラメータは次のとおりです。

  • 失敗数(OUT変数)

  • 依存する表

  • リフレッシュ方法: F-Fast、P-Fast_PCT、?-Force、C-Complete

  • 使用するロールバック・セグメント

  • エラー発生後のリフレッシュ(TRUEまたはFALSE)

    ブール・パラメータ。TRUEに設定すると、number_of_failures出力パラメータは失敗したリフレッシュの数に設定され、通常のエラー・メッセージによって失敗の発生が示されます。インスタンスに関するアラート・ログに、リフレッシュ・エラーの詳細が示されます。デフォルト値のFALSEに設定すると、最初にエラーが発生したときにリフレッシュが停止し、リスト内の残りのマテリアライズド・ビューはリフレッシュされません。

  • アトミック・リフレッシュ(TRUEまたはFALSE)

    TRUEに設定すると、すべてのリフレッシュが1トランザクションで行われます。FALSEに設定すると、指定したマテリアライズド・ビューのリフレッシュがそれぞれ別のトランザクションで行われます。FALSEに設定すると、パラレルDMLによってリフレッシュが最適化され、マテリアライズド・ビューのDDLが切り捨てられます。マテリアライズド・ビューをアトミック・モードでリフレッシュする際、リライト整合性モードがstale_toleratedに設定されている場合にクエリー・リライトを使用できます。リフレッシュがネステッド・ビューで実行される場合は、アトミック・リフレッシュは保証されません。

  • ネストされているかどうか

    TRUEに設定すると、依存順序に基づいて指定した表のセットのすべての依存マテリアライズド・ビューがリフレッシュされ、マテリアライズド・ビューが実表に対して最新の状態になります。

customers表を参照するすべてのマテリアライズド・ビューの完全リフレッシュを実行するには、次のように指定します。

DBMS_MVIEW.REFRESH_DEPENDENT(failures, 'CUSTOMERS', 'C', '', FALSE, FALSE );

リフレッシュへのジョブ・キューの使用

ジョブ・キューを使用して、複数のマテリアライズド・ビューをパラレルにリフレッシュできます。キューが使用できない場合、高速リフレッシュでは各ビューがフォアグラウンド・プロセスで順次リフレッシュされます。キューを使用可能にするには、JOB_QUEUE_PROCESSESパラメータを設定する必要があります。このパラメータでバックグラウンド・ジョブ・キュー・プロセスの数を定義することにより、同時に実行可能なマテリアライズド・ビューの数が決まります。同時リフレッシュの数と各リフレッシュの並列度のバランスが調整されます。マテリアライズド・ビューがリフレッシュされる順序は、ネステッド・マテリアライズド・ビューで指定されている依存性、および他のマテリアライズド・ビューに対するクエリー・リライトによる効率的なリフレッシュの可能性によって決まります(詳細は、「リフレッシュのスケジューリング」を参照)。このパラメータが有効なのは、atomic_refreshFALSEに設定されている場合のみです。

DBMS_MVIEW.REFRESHを実行中のプロセスに割込みが入るか、そのインスタンスが停止すると、ジョブ・キュー・プロセスで実行中だったリフレッシュ・ジョブが再度キューに入れられ、引き続き実行されます。これらのジョブを削除するには、DBMS_JOB.REMOVEプロシージャを使用します。

高速リフレッシュが可能なパターン

すべてのマテリアライズド・ビューの高速リフレッシュが可能であるとは限りません。したがって、パッケージDBMS_MVIEW.EXPLAIN_MVIEWを使用して、マテリアライズド・ビューに使用可能なリフレッシュ方法を判断します。DBMS_MVIEWパッケージの詳細は、第9章「基本的なマテリアライズド・ビュー」を参照してください。

マテリアライズド・ビューを高速リフレッシュできるようにする方法がわからない場合は、DBMS_ADVISOR.TUNE_MVIEWプロシージャを使用して、高速リフレッシュできるマテリアライズド・ビューの作成に必要な文を含むスクリプトを指定します。詳細は、『Oracle Databaseパフォーマンス・チューニング・ガイド』を参照してください。

パラレル化の推奨初期化パラメータ

パラレル化を効果的にするには、次の初期化パラメータを正しく設定する必要があります。

  • PARALLEL_MAX_SERVERSは、パラレル化に対応できるように十分高い値にします。リフレッシュ文に必要なスレーブの数を考慮する必要があります。たとえば、並列度が8であれば、16のスレーブ・プロセスが必要です。

  • インスタンスでソートと結合のメモリー使用を自動的に管理するには、PGA_AGGREGATE_TARGETを設定する必要があります。メモリー・パラメータを手動で設定する場合は、SORT_AREA_SIZEHASH_AREA_SIZE未満にする必要があります。

  • OPTIMIZER_MODEは、all_rowsと同じ値にします。

すべての表および索引を効率的に分析すると、最適化が向上します。


関連項目:

詳細は、『Oracle Database VLDBおよびパーティショニング・ガイド』を参照してください。

リフレッシュの監視

ジョブの実行中は、V$SESSION_LONGOPSビューを問い合せて、各マテリアライズド・ビューのリフレッシュの進行状況を確認できます。

SELECT * FROM V$SESSION_LONGOPS;

どのジョブがどのキューに入っているかを確認するには、次の文を使用します。

SELECT * FROM DBA_JOBS_RUNNING;

マテリアライズド・ビューのステータスのチェック

マテリアライズド・ビューのステータスをチェックできるように、DBA_MVEIWSALL_MVIEWSUSER_MVIEWSの3つのビューが用意されています。マテリアライズド・ビューが最新か失効しているかをチェックするには、次の文を発行します。

SELECT MVIEW_NAME, STALENESS, LAST_REFRESH_TYPE, COMPILE_STATE 
FROM USER_MVIEWS ORDER BY MVIEW_NAME;

MVIEW_NAME            STALENESS      LAST_REF       COMPILE_STATE
----------            ---------      --------       -------------
CUST_MTH_SALES_MV     NEEDS_COMPILE  FAST           NEEDS_COMPILE
PROD_YR_SALES_MV      FRESH          FAST           VALID

compile_state列がNEEDS COMPILEとなっている場合、表示されているその他の列の値は信頼できず、実際のステータスが反映されていない場合があります。マテリアライズド・ビューを再検証するには、次の文を発行します。

ALTER MATERIALIZED VIEW [materialized_view_name] COMPILE;

続いて、SELECT文を再度発行します。

パーティションの最新状態の表示

一部のビューでは、実表のパーティションの状態を確認し、マテリアライズド・ビューのデータの最新および失効の範囲を判別できます。該当のビューは次のとおりです。

  • *_USER_MVIEWS

    マテリアライズド・ビューのパーティション・チェンジ・トラッキング(PCT)情報の判別に使用します。

  • *_USER_MVIEW_DETAIL_RELATIONS

    マテリアライズド・ビューの基になるディテール表のパーティション情報を表示するのに使用します。

  • *_USER_MVIEW_DETAIL_PARTITION

    最新のパーティションを判別するのに使用します。

  • *_USER_MVIEW_DETAIL_SUBPARTITION

    最新のサブパーティションを判別するのに使用します。

これらのビューの使用例を次に示します。図16-1は、レンジ-リスト・パーティション化された表とそれに基づくマテリアライズド・ビューを示しています。P1、P2、P3はパーティションで、SP1、SP2、SP3はサブパーティションです。

図16-1 PCTによる最新状態の判別

図16-1の説明は図の下のリンクをクリックしてください。
「図16-1 PCTによる最新状態の判別」の説明

最新状態の判別に使用するビューの使用例

この項では、マテリアライズド・ビューとそのディテール表のPCTおよび最新状態の情報を判別するための例を示します。

例16-8 マテリアライズド・ビューのPCTステータスの確認

マテリアライズド・ビューのPCT情報にアクセスするには、次のようにUSER_MVIEWSを問い合せます。

SELECT MVIEW_NAME, NUM_PCT_TABLES, NUM_FRESH_PCT_REGIONS,
   NUM_STALE_PCT_REGIONS
FROM USER_MVIEWS
WHERE MVIEW_NAME = MV1;

MVIEW_NAME NUM_PCT_TABLES NUM_FRESH_PCT_REGIONS NUM_STALE_PCT_REGIONS
---------- -------------- --------------------- ---------------------
       MV1              1                     9                     3

例16-9 マテリアライズド・ビューのディテール表におけるPCTステータスの確認

PCTディテール表の情報にアクセスするには、次のようにUSER_MVIEW_DETAIL_RELATIONSを問い合せます。

SELECT MVIEW_NAME, DETAILOBJ_NAME, DETAILOBJ_PCT,
   NUM_FRESH_PCT_PARTITIONS, NUM_STALE_PCT_PARTITIONS
FROM USER_MVIEW_DETAIL_RELATIONS
WHERE MVIEW_NAME = MV1;
MVIEW_NAME  DETAILOBJ_NAME  DETAIL_OBJ_PCT  NUM_FRESH_PCT_PARTITIONS  NUM_STALE_PCT_PARTITIONS
----------  --------------  --------------  ------------------------  ------------------------
        MV1             T1               Y                         3                         1

例16-10 最新のパーティションの確認

パーティションのPCTの最新状態の情報にアクセスするには、次のようにUSER_MVIEW_DETAIL_PARTITIONを問い合せます。

SELECT MVIEW_NAME,DETAILOBJ_NAME,DETAIL_PARTITION_NAME,
   DETAIL_PARTITION_POSITION,FRESHNESS
FROM USER_MVIEW_DETAIL_PARTITION
WHERE MVIEW_NAME = MV1;
MVIEW_NAME  DETAILOBJ_NAME  DETAIL_PARTITION_NAME  DETAIL_PARTITION_POSITION  FRESHNESS
----------  --------------  ---------------------  -------------------------  ---------
       MV1               T1                    P1                          1      FRESH
       MV1               T1                    P2                          2      FRESH
       MV1               T1                    P3                          3      STALE
       MV1               T1                    P4                          4      FRESH

例16-11 最新のサブパーティションの確認

サブパーティションのPCTの最新状態の情報にアクセスするには、次のようにUSER_MVIEW_DETAIL_SUBPARTITIONを問い合せます。

SELECT MVIEW_NAME,DETAILOBJ_NAME,DETAIL_PARTITION_NAME, DETAIL_SUBPARTITION_NAME,
    DETAIL_SUBPARTITION_POSITION,FRESHNESS
FROM USER_MVIEW_DETAIL_SUBPARTITION
WHERE MVIEW_NAME = MV1;
MVIEW_NAME DETAILOBJ DETAIL_PARTITION DETAIL_SUBPARTITION_NAME DETAIL_SUBPARTITION_POS FRESHNESS
---------- --------- ---------------- ------------------------ ----------------------- ---------
       MV1        T1               P1                      SP1                       1     FRESH
       MV1        T1               P1                      SP2                       1     FRESH
       MV1        T1               P1                      SP3                       1     FRESH
       MV1        T1               P2                      SP1                       1     FRESH
       MV1        T1               P2                      SP2                       1     FRESH
       MV1        T1               P2                      SP3                       1     FRESH
       MV1        T1               P3                      SP1                       1     STALE
       MV1        T1               P3                      SP2                       1     STALE
       MV1        T1               P3                      SP3                       1     STALE
       MV1        T1               P4                      SP1                       1     FRESH
       MV1        T1               P4                      SP2                       1     FRESH
       MV1        T1               P4                      SP3                       1     FRESH

リフレッシュのスケジューリング

ほとんどの場合、データベースには複数のマテリアライズド・ビューがあります。一部のマテリアライズド・ビューは、他のマテリアライズド・ビューに対してリライトして計算されているものもあります。これは、ネステッド・マテリアライズド・ビューがある、または一部の階層の異なるレベルにマテリアライズド・ビューがあるデータ・ウェアハウス環境では、非常に一般的なことです。

このような場合、BUILD DEFERREDとしてマテリアライズド・ビューを作成し、DBMS_MVIEWパッケージのいずれかのリフレッシュ・プロシージャを発行してすべてのマテリアライズド・ビューをリフレッシュする必要があります。Oracle Databaseによって、依存性が計算され、正しい順序でマテリアライズド・ビューがリフレッシュされます。「階層的キューブのマテリアライズド・ビューの例」で説明されている完全な階層的キューブの例を参照してください。すべてのマテリアライズド・ビューがBUILD DEFERREDとして作成されているとします。マテリアライズド・ビューをBUILD DEFERREDとして作成すると、すべてのマテリアライズド・ビューのメタデータのみが作成されます。これで、DBMS_MVIEWパッケージのリフレッシュ・プロシージャのいずれかをコールし、すべてのマテリアライズド・ビューを正しい順序でリフレッシュできます。

DECLARE numerrs PLS_INTEGER;
BEGIN DBMS_MVIEW.REFRESH_DEPENDENT (
   number_of_failures => numerrs, list=>'SALES', method => 'C');
DBMS_OUTPUT.PUT_LINE('There were ' || numerrs || ' errors during refresh');
END;
/

プロシージャは、マテリアライズド・ビューを依存性の順序(sales_hierarchical_mon_cube_mvから始まり、sales_hierarchical_qtr_cube_mvsales_hierarchical_yr_cube_mvsales_hierarchical_all_cube_mvという順序)でリフレッシュします。各マテリアライズド・ビューは、リストにおける1つ前のマテリアライズド・ビューに対してリライトされます。

同じ種類のリライトは、PCTリフレッシュを行う際にも使用できます。PCTリフレッシュでは、ディテール表で変更された行に対応するマテリアライズド・ビューの行が再計算されます。リフレッシュ時に最新のマテリアライズド・ビューが他にある場合は、ディテール表ではなくそのマテリアライズド・ビューが直接使用されます。

したがって、指定した方法に関係なく、マテリアライズド・ビューのリストをDBMS_MVIEWパッケージのいずれかのリフレッシュ・プロシージャに渡すことは有益です。これによって、プロシージャは、マテリアライズド・ビューに対してリフレッシュを実行する順序を認識できます。

集計を含むマテリアライズド・ビューのリフレッシュのヒント

ここでは、集計を含むマテリアライズド・ビューのリフレッシュ機能を使用する場合のガイドラインを示します。

  • 高速リフレッシュの場合は、ROWIDSEQUENCEおよびINCLUDING NEW VALUES句を使用して、マテリアライズド・ビューに関連するすべてのディテール表のマテリアライズド・ビュー・ログを作成します。

    マテリアライズド・ビュー・ログには、マテリアライズド・ビューに使用されると思われる表の列をすべて含めます。

    高速リフレッシュは、マテリアライズド・ビュー・ログでSEQUENCEオプションが省略されていても可能な場合があります。すべてのディテール表で挿入または削除しか発生しないと判断できる場合、マテリアライズド・ビュー・ログにはSEQUENCE句は不要です。ただし、複数の表が更新される可能性があるか必要な場合、または特定の更新の手順が不明な場合は、SEQUENCE句が含まれているかどうかを確認してください。

  • Oracleのバルク・ロード・ユーティリティまたはダイレクト・パス・インサート(ロードに対するAPPENDヒント付きのINSERT)を使用します。

    これは、従来の挿入に比べてはるかに効率的です。ロード中はすべての制約を使用禁止にし、ロード終了後に使用可能に戻します。ダイレクト・ロードと従来型DMLのどちらを使用する場合も、マテリアライズド・ビュー・ログは必要であるため注意してください。

    マテリアライズド・ビューに対する従来型の複合DML操作、ダイレクト・パス・インサートおよび高速リフレッシュの順序を最適化してください。従来のDMLおよびダイレクト・ロードと混在させて高速リフレッシュを使用できます。高速リフレッシュでは、次に示すように、ダイレクト・ロードのみが発生することがわかっていれば、大幅な最適化を実行できます。

    1. ディテール表へのダイレクト・パス・インサート(SQL*LoaderまたはINSERT /*+ APPEND */)を行います。

    2. マテリアライズド・ビューのリフレッシュ

    3. 従来型の複合DML操作を行います。

    4. マテリアライズド・ビューのリフレッシュ

    高速リフレッシュを、ディテール表に対する従来型の複合DML(INSERTUPDATEおよびDELETE)と併用できます。ただし、高速リフレッシュで処理中に大幅な最適化を実行できるのは、次のように、表に対して挿入または削除のみが行われていることが検出される場合です。

    • ディテール表に対するDML INSERTまたはDELETE

    • 複数のマテリアライズド・ビューのリフレッシュ

    • ディテール表のDML更新

    • マテリアライズド・ビューのリフレッシュ

    さらに最適化するには、INSERTDELETEを分離します。

    可能であれば、最後にリフレッシュを1つのみ発行するのではなく、前述のように各種のデータ変更の後にリフレッシュを実行します。可能でない場合は、従来のDMLを挿入対象の表に限定すると、リフレッシュのパフォーマンスが大幅に改善されます。DELETEとダイレクト・ロードの混在を回避してください。

    さらに、ON COMMITリフレッシュの場合、Oracleは、コミットされたトランザクションで実行されたDMLのタイプを記録します。したがって、同じトランザクションの他の表には、ダイレクト・パス・インサートおよびDMLを実行しないでください。Oracleがリフレッシュ・フェーズを最適化できない可能性があります。

    ON COMMITマテリアライズド・ビューの場合は、各トランザクションの最後にリフレッシュが自動的に発生します。DML文を分離できない場合があり、その場合はトランザクションを短くすると有効です。ただし、ディテール表に対して多数の変更を行う場合は、更新のたびにリフレッシュするより、それらの更新を1回のトランザクションで実行し、コミット時に一度にマテリアライズド・ビューをリフレッシュする方が効率的です。

  • 次の方法を使用できるため、表をパーティション化することをお薦めします。

    • パラレルDML

      大量のロードまたはリフレッシュの場合は、パラレルDMLを使用可能にすると、処理時間を短縮できます。

    • パーティション・チェンジ・トラッキング(PCT)高速リフレッシュ

      マテリアライズド・ビューの高速リフレッシュは、ディテール表に対するパーティション・メンテナンス操作後に実行できます。マテリアライズド・ビューにPCTを使用可能にする方法の詳細は、「パーティション・チェンジ・トラッキング」を参照してください。

  • また、マテリアライズド・ビューをパーティション化すると、リフレッシュでパラレルDMLを使用してマテリアライズド・ビューを更新できるため、パフォーマンスが改善されます。たとえば、ディテール表とマテリアライズド・ビューがパーティション化されており、PARALLEL句があるとします。次の順序により、Oracleではマテリアライズド・ビューのリフレッシュをパラレル化できます。

    1. ディテール表にバルク・ロードします。

    2. ALTER SESSION ENABLE PARALLEL DML文でパラレルDMLを使用可能にします。

    3. マテリアライズド・ビューをリフレッシュします。

  • DBMS_MVIEW.REFRESHを使用してリフレッシュを行うには、パラメータatomic_refreshFALSEに設定します。

    • COMPLETEリフレッシュでは、これにより、マテリアライズド・ビューの既存の行がTRUNCATEによって削除されます。これはDELETEより高速です。

    • PCTリフレッシュでは、マテリアライズド・ビューが適切にパーティション化されている場合は、これにより、マテリアライズド・ビューの影響を受けるパーティションの行がTRUNCATE PARTITIONによって削除されます。これはDELETEより高速です。

    • FASTまたはFORCEリフレッシュでは、COMPLETEリフレッシュまたはPCTリフレッシュが選択された場合、これにより、前述のTRUNCATE最適化を使用できます。

  • JOB_QUEUESを指定してDBMS_MVIEW.REFRESHを使用する場合は、atomicFALSEに設定してください。このように設定しなければ、JOB_QUEUESは使用されません。ジョブ・キュー・プロセスの数を、プロセッサ数より大きくなるように設定します。

    ジョブ・キューが使用可能になっており、リフレッシュするマテリアライズド・ビューが多い場合は、個別にコールするより1つのコマンドですべてをリフレッシュするほうが高速です。

  • リフレッシュしたマテリアライズド・ビューをクエリー・リライトで使用できるようにするには、REFRESH FORCEを使用します。最適なリフレッシュ方法が選択されます。高速リフレッシュができない場合は、完全リフレッシュが行われます。

  • 1回のプロシージャ・コールで、すべてのマテリアライズド・ビューをリフレッシュします。これにより、ネステッド・マテリアライズド・ビューで指定された依存性、および他のマテリアライズド・ビューに対するクエリー・リライトを使用した効率的なリフレッシュを考慮した正しい順序によるすべてのマテリアライズド・ビューのリフレッシュが、Oracleによってスケジューリングされます。

集計を含まないマテリアライズド・ビューのリフレッシュのヒント

結合を含み、集計を含まないマテリアライズド・ビューは、集計を含むマテリアライズド・ビューよりもかなりサイズが大きくなる傾向があるため、ディテール表の結合列ROWIDのそれぞれに索引を設定すると、リフレッシュ・パフォーマンスが大幅に向上します。たとえば、次のマテリアライズド・ビューを考えてみます。

CREATE MATERIALIZED VIEW detail_fact_mv BUILD IMMEDIATE AS
SELECT s.rowid "sales_rid", t.rowid "times_rid", c.rowid "cust_rid",
   c.cust_state_province, t.week_ending_day, s.amount_sold
FROM sales s, times t, customers c 
WHERE s.time_id = t.time_id AND s.cust_id = c.cust_id;
 

この場合は、sales_ridtimes_ridおよびcust_rid列に索引を作成します。リフレッシュを起動する前に、セッションでのパラレルDMLを可能にするとともにパーティション化も行ってください。リフレッシュ・パフォーマンスが大幅に向上します。

このタイプのマテリアライズド・ビューは、DMLがディテール表に実行される場合でも高速リフレッシュも可能です。このタイプのマテリアライズド・ビューでも、単一表集計マテリアライズド・ビューと同じ手順に従ってください。つまり、1つのタイプの変更(ダイレクト・パス・インサートまたはDML)を行うたびにマテリアライズド・ビューをリフレッシュします。これは、Oracle Databaseが、1つのタイプの変更のみが行われたと検出した場合に、大幅な最適化を行うためです。

また、複数の表をすべてロードしてからリフレッシュを行うより、表を1つロードするたびにリフレッシュを起動することをお薦めします。

ON COMMITリフレッシュの場合、Oracleは、コミットされたトランザクションで実行されたDMLのタイプを記録します。そのため、同じトランザクションの他の表には、できるだけダイレクト・パス・ロードおよび従来型DMLを実行しないでください。Oracleがリフレッシュ・フェーズを最適化できない可能性があります。たとえば、次のような方法はお薦めできません。

  1. ファクト表への新規データのダイレクト・ロード

  2. 記憶域表へのDML

  3. コミット

また、異なるタイプの従来型DML文は、できるだけ混在させないでください。これも、高速リフレッシュ時の様々な最適化を妨げる要因になります。たとえば、次のような文は使用しないでください。

  1. ファクト表への挿入

  2. ファクト表からの削除

  3. コミット

多数の更新が必要な場合は、できるだけ1回のトランザクションにまとめてください。これによって、リフレッシュは、更新のたびにではなく、コミット時に1回のみで済みます。

データ・ウェアハウス環境では、マテリアライズド・ビューがパラレル句を含む場合、次の手順で行うことをお薦めします。

  1. ファクト表にバルク・ロードします。

  2. パラレルDMLを使用可能にします。

  3. ALTER SESSION ENABLE PARALLEL DML文を発行します。

  4. マテリアライズド・ビューをリフレッシュします。

ネステッド・マテリアライズド・ビューのリフレッシュのヒント

ネステッド・マテリアライズド・ビューのベースとなるオブジェクトは、マテリアライズド・ビューのリフレッシュ時にはすべて通常の表として扱われます。ON COMMITリフレッシュ・オプションが指定されている場合は、すべてのマテリアライズド・ビューがコミット時に適切な順番でリフレッシュされます。Oracleは、一部順序付けられたマテリアライズド・ビューの集合を作成し、リフレッシュ完了後にはすべてのマテリアライズド・ビューが最新になっているように、リフレッシュを行います。マテリアライズド・ビューの状態は、適切なビュー(USERDBA_ALL_MVIEWS)に問い合せることでチェックできます。

マテリアライズド・ビューのいずれかがON DEMANDリフレッシュとして定義されている場合(リフレッシュ方法がFASTFORCECOMPLETEのいずれであるかにかかわらず)、ネステッド・マテリアライズド・ビューは、(最新かどうかにかかわらず)他のマテリアライズド・ビューの現在の内容との比較によってリフレッシュされます。そのため、正しい順番で(マテリアライズド・ビュー間の依存性を考慮して)リフレッシュする必要があります。これには、ネストされた階層の一番上にあるマテリアライズド・ビューに対してリフレッシュ・プロシージャを呼び出し、nestedパラメータをTRUEに指定します。

コミット中にリフレッシュに失敗した場合は、リフレッシュされていないマテリアライズド・ビューのリストがアラート・ログに書き込まれます。それらをすべて依存マテリアライズド・ビューとともに手動でリフレッシュする必要があります。

ネステッド・マテリアライズド・ビューのリフレッシュには、通常のマテリアライズド・ビューの場合と同じDBMS_MVIEWプロシージャを使用します。

これらのプロシージャは、ネステッド・マテリアライズド・ビューに対して使用されると、次のように動作します。

  • 他のマテリアライズド・ビュー上に作成されているマテリアライズド・ビューmy_mvREFRESHが適用されると、my_mvは、nested => TRUEを指定しないかぎり、他のマテリアライズド・ビューの現在の内容を反映するようにリフレッシュされます(つまり、他のマテリアライズド・ビューが最初にリフレッシュされることはありません)。

  • REFRESH_DEPENDENTをマテリアライズド・ビューmy_mvに適用すると、nested => TRUEを指定しないかぎり、my_mvに直接依存しているマテリアライズド・ビューのみがリフレッシュされます(my_mvに依存しているマテリアライズド・ビューにさらに依存しているマテリアライズド・ビューはリフレッシュされません)。

  • REFRESH_ALL_MVIEWSを使用すると、マテリアライズド・ビューがリフレッシュされる順序は、ネステッド・マテリアライズド・ビュー間の依存性が考慮されます。

  • GET_MV_DEPENDENCIESで、あるオブジェクトに直接依存するマテリアライズド・ビューのリストが作成されます。

UNION ALLでの高速リフレッシュのヒント

マテリアライズド・ビュー定義にメンテナンス列を指定することで、UNION ALLを使用するマテリアライズド・ビューに高速リフレッシュを使用できます。たとえば、UNION ALL演算子を持つマテリアライズド・ビューは、次のように高速リフレッシュできます。

CREATE MATERIALIZED VIEW fast_rf_union_all_mv AS
SELECT x.rowid AS r1, y.rowid AS r2, a, b, c, 1 AS marker
FROM x, y WHERE x.a = y.b 
UNION ALL 
SELECT p.rowid, r.rowid, a, c, d, 2 AS marker
FROM p, r WHERE p.a = r.y;

メンテナンス・マーカー列(例ではMARKER)の形式は、numeric_or_string_literal AS column_aliasである必要があります。ここで各UNION ALLメンバーは、numeric_or_string_literalに対して別個の値を持ちます。

コミットSCNベースのマテリアライズド・ビュー・ログを使用した高速リフレッシュのヒント

実表のマテリアライズド・ビュー・ログにWITH COMMIT SCN句を含めるようにすると、多くの場合、高速リフレッシュのパフォーマンスを大幅に改善できます。WITH COMMIT SCNを使用してマテリアライズド・ビュー・ログの処理を最適化することで、高速リフレッシュの処理時間を短縮できます。次の例は、この句の使用方法を示しています。

CREATE MATERIALIZED VIEW LOG ON sales WITH ROWID
 (prod_id, cust_id, time_id, channel_id, promo_id, quantity_sold, amount_sold),
COMMIT SCN INCLUDING NEW VALUES;

マテリアライズド・ビューのリフレッシュではコミットSCNベースのマテリアライズド・ビュー・ログが自動的に使用されるので、リフレッシュ時間が短縮されます。

COMMIT SCNを利用できるのは、新しいマテリアライズド・ビュー・ログのみです。既存のマテリアライズド・ビュー・ログの場合は、削除して再作成しないかぎり、変更してCOMMIT SCNを追加できません。

タイムスタンプ・ベースのマテリアライズド・ビュー・ログを使用した実表とコミットSCNベースのマテリアライズド・ビュー・ログを使用した実表の両方でマテリアライズド・ビューが作成されると、エラー(ORA-32414)が発生し、これらのマテリアライズド・ビュー・ログが高速リフレッシュに関して相互に互換性がないことを示すメッセージが表示されます。

マテリアライズド・ビューのリフレッシュ後のヒント

ロードまたは増分ロードを行い、ディテール表索引を再作成した後は、整合性制約(ある場合)を使用可能に戻し、そのディテール表から導出されたマテリアライズド・ビューおよびマテリアライズド・ビュー索引をリフレッシュする必要があります。データ・ウェアハウス環境では、参照整合性制約は、通常、NOVALIDATEまたはRELYオプションで使用可能にできます。リフレッシュ操作を行う前に、そのリフレッシュ操作をリカバリ可能にする必要があるかどうかを決定する必要があります。マテリアライズド・ビューのデータは冗長で、いつでもディテール表から再作成できるため、マテリアライズド・ビューのロギングは使用禁止にすることをお薦めします。ロギングを無効にし、増分リフレッシュをリカバリの必要なしで実行するには、リフレッシュの前にALTER MATERIALIZED VIEW ... NOLOGGING文を使用します。

ON COMMIT方法でマテリアライズド・ビューをリフレッシュする場合は、リフレッシュ操作後、アラート・ログalert_SID.logおよびトレース・ファイルora_SID_number.trcで、エラーが発生していないかどうかをチェックします。

パーティション表付きマテリアライズド・ビューの使用

データ・ウェアハウスの主なメンテナンス・コンポーネントは、ディテール・データの変更時におけるマテリアライズド・ビューの同期化(リフレッシュ)です。このとき基礎となるディテール表をパーティション化していると、リフレッシュ・タスクの所要時間を短縮できます。これは、パーティション化によりパラレルDMLを使用してマテリアライズド・ビューを更新できるようになるためです。また、パーティション・チェンジ・トラッキングも使用可能になります。

パーティション・チェンジ・トラッキングの高速リフレッシュ

データ・ウェアハウスでは、通常、ディテール表の変更により、DROPEXCHANGEMERGEおよびADD PARTITIONなどのパーティション・メンテナンス操作が必要になります。このような操作の後でマテリアライズド・ビューをメンテナンスするには、手動メンテナンス(CONSIDER FRESHも参照)または完全リフレッシュを使用する必要がありました。現在では、パーティション・チェンジ・トラッキング(PCT)リフレッシュと呼ばれる高速リフレッシュ機能を使用できます。

PCTを使用可能にするには、ディテール表をパーティション化する必要があります。この機能では、マテリアライズド・ビュー自体をパーティション化する必要はありません。PCTリフレッシュが可能な場合は、ユーザーに対して透過的に処理が発生します。PCTの要件は、「パーティション・チェンジ・トラッキング」を参照してください。

この機能の使用例を次に示します。「PCT高速リフレッシュの使用例1」で、salestime_id列を使用してパーティション化された表で、productsprod_category列でパーティション化されています。表timesはパーティション表ではありません。

PCT高速リフレッシュの使用例1

  1. 次のマテリアライズド・ビューは、PCTの要件を満たしています。

    CREATE MATERIALIZED VIEW cust_mth_sales_mv
    BUILD IMMEDIATE
    REFRESH FAST ON DEMAND
    ENABLE QUERY REWRITE AS
    SELECT s.time_id, s.prod_id, SUM(s.quantity_sold), SUM(s.amount_sold),
           p.prod_name, t.calendar_month_name, COUNT(*),
           COUNT(s.quantity_sold), COUNT(s.amount_sold)
    FROM sales s, products p, times t
    WHERE  s.time_id = t.time_id AND s.prod_id = p.prod_id
    GROUP BY t.calendar_month_name, s.prod_id, p.prod_name, s.time_id;
    
  2. DBMS_MVIEW.EXPLAIN_MVIEWプロシージャを使用すると、PCTリフレッシュが可能な表を判断できます。

    MVNAME              CAPABILITY_NAME   POSSIBLE  RELATED_TEXT  MSGTXT
    -----------------   ---------------   --------  ------------  ----------------
    CUST_MTH_SALES_MV   PCT               Y         SALES
    CUST_MTH_SALES_MV   PCT_TABLE         Y         SALES
    CUST_MTH_SALES_MV   PCT_TABLE         N         PRODUCTS      no partition key
                                                                  or PMARKER
                                                                  in SELECT list
    CUST_MTH_SALES_MV   PCT_TABLE         N         TIMES         relation is not
                                                                  partitionedtable
    

    EXPLAIN_MVIEWから抜粋したサンプル出力からもわかるように、sales表に対して実行されるパーティション・メンテナンス操作では、PCT高速リフレッシュが可能です。ただし、products表に対するパーティション・メンテナンス操作や更新の後は、cust_mth_sales_mvに十分な情報が含まれていないため、PCTリフレッシュは実行できません。times表はパーティション化されていないため、PCTリフレッシュできないことに注意してください。Oracle DatabaseでPCTリフレッシュが適用されるのは、更新されたすべての表に関してPCTをサポートするだけの十分な情報がマテリアライズド・ビューにあると判断できる場合です。DBA_MVIEWSDBA_MVIEW_DETAIL_PARTITIONなどのビューを使用すると、最新および失効したパーティションを確認できます。

    このプロシージャの使用方法およびPCT関連のビューの詳細は、「マテリアライズド・ビュー機能の分析」を参照してください。

  3. 少し後の時点で、sales表の1つのパーティションのSPLIT操作が必要になったとします。

    ALTER TABLE SALES
    SPLIT PARTITION month3 AT (TO_DATE('05-02-1998', 'DD-MM-YYYY'))
    INTO (PARTITION month3_1 TABLESPACE summ,
          PARTITION month3 TABLESPACE summ);
     
    
  4. sales表になんらかのデータを挿入します。

  5. DBMS_MVIEW.REFRESHプロシージャを使用して、cust_mth_sales_mvを高速リフレッシュします。

    EXECUTE DBMS_MVIEW.REFRESH('CUST_MTH_SALES_MV', 'F',
       '',TRUE,FALSE,0,0,0,FALSE);
    

この使用例では、高速リフレッシュを行うとPCTリフレッシュが自動的に実行されます。ただし、パーティション・メンテナンス操作によって表が更新され、PCTが不可能な場合には、高速リフレッシュは行われません。これについては、「PCT高速リフレッシュの使用例2」を参照してください。

「PCT高速リフレッシュの使用例1」は、次のように、PMARKER句を使用してマテリアライズド・ビューを作成した場合にも該当します。

CREATE MATERIALIZED VIEW cust_sales_marker_mv
BUILD IMMEDIATE
REFRESH FAST ON DEMAND
ENABLE QUERY REWRITE AS
SELECT DBMS_MVIEW.PMARKER(s.rowid) s_marker, SUM(s.quantity_sold),
  SUM(s.amount_sold), p.prod_name, t.calendar_month_name, COUNT(*),
  COUNT(s.quantity_sold), COUNT(s.amount_sold)
FROM sales s, products p, times t
WHERE  s.time_id = t.time_id AND s.prod_id = p.prod_id
GROUP BY DBMS_MVIEW.PMARKER(s.rowid),
         p.prod_name, t.calendar_month_name;

PCT高速リフレッシュの使用例2

「PCT高速リフレッシュの使用例2」の最初の3つの手順は、「PCT高速リフレッシュの使用例1」と同じです。その後、sales表に対するパーティションのSPLIT操作を実行します。ただし、マテリアライズド・ビューをリフレッシュする前に、times表にレコードを挿入します。

  1. 「PCT高速リフレッシュの使用例1」の場合と同じです。

  2. 「PCT高速リフレッシュの使用例1」の場合と同じです。

  3. 「PCT高速リフレッシュの使用例1」の場合と同じです。

  4. 「PCT高速リフレッシュの使用例1」と同じSPLIT操作の発行後に、times表になんらかのデータを挿入します。

    ALTER TABLE SALES
    SPLIT PARTITION month3 AT (TO_DATE('05-02-1998', 'DD-MM-YYYY'))
    INTO (PARTIITION month3_1 TABLESPACE summ,
          PARTITION month3 TABLESPACE summ);
    
  5. cust_mth_sales_mvをリフレッシュします。

    EXECUTE DBMS_MVIEW.REFRESH('CUST_MTH_SALES_MV', 'F',
        '',TRUE,FALSE,0,0,0,FALSE);
    ORA-12052: cannot fast refresh materialized view SH.CUST_MTH_SALES_MV
    

PCT高速リフレッシュを実行できない表に対してDMLが発生しているため、このマテリアライズド・ビューは高速リフレッシュできません。この状況を回避するには、PCT高速リフレッシュが使用可能になっているディテール表に対するパーティション・メンテナンス操作の直後に、高速リフレッシュを実行することをお薦めします。

「PCT高速リフレッシュの使用例2」の状況が発生した場合は、2つの方法が考えられます。つまり、完全リフレッシュを実行するか、後述のようにCONSIDER FRESHオプションに切り替えるかです。ただし、CONSIDER FRESHとパーティション・チェンジ・トラッキングの高速リフレッシュには、互換性がないため注意する必要があります。ALTER MATERIALIZED VIEW cust_mth_sales_mv CONSIDER FRESH文が発行されると、完全リフレッシュが完了するまで、このマテリアライズド・ビューにはPCTリフレッシュが適用されなくなります。さらに、手動でマテリアライズド・ビューをリフレッシュしないかぎり、CONSIDER FRESHを使用しないでください。

データ・ウェアハウスで一般的な状況は、データのローリング・ウィンドウを使用することです。この場合、たとえばディテール表とマテリアライズド・ビューに過去12か月分のデータが含まれる場合があります。毎月、1か月分の新規データが表に追加され、最も古い月が削除(またはアーカイブ)されます。PCTリフレッシュは、この場合にマテリアライズド・ビューをメンテナンスする非常に効率的なメカニズムです。

PCT高速リフレッシュの使用例3

  1. 通常、新規データは、新規パーティションを追加し、それを新規データを含む表と交換することでディテール表に追加されます。

    ALTER TABLE sales ADD PARTITION month_new ...
    ALTER TABLE sales EXCHANGE PARTITION month_new month_new_table
      
    
  2. 次に、最も古いパーティションが削除されるか切り捨てられます。

    ALTER TABLE sales DROP PARTITION month_oldest;
    
  3. ここで、マテリアライズド・ビューがPCTリフレッシュの要件をすべて満たしているとします。

    EXECUTE DBMS_MVIEW.REFRESH('CUST_MTH_SALES_MV', 'F', '', TRUE, FALSE,0,0,0,FALSE);
    

高速リフレッシュでは、PCTが使用可能であることが自動的に検出され、PCTリフレッシュが実行されます。

CONSIDER FRESHの高速リフレッシュ

データ・ウェアハウスでは、通常、履歴情報がディテール表になくなっても、この情報をマテリアライズド・ビューに累積する必要があります。この場合は、ALTER MATERIALIZED VIEW materialized_view_name CONSIDER FRESH文を使用して、マテリアライズド・ビューをメンテナンスできます。

CONSIDER FRESHでは、マテリアライズド・ビューの内容がFRESHである(ディテール表と同期している)と宣言していることに注意してください。このオプションをこのような場合にクエリー・リライトと併用すると、予期しない結果になる可能性があるため注意が必要です。

履歴データがある場合にCONSIDER FRESHを使用した後、DMLやダイレクト・ロード後の従来の高速リフレッシュをマテリアライズド・ビューに適用することは可能ですが、PCT高速リフレッシュは実行できません。これは、ある時点にディテール表のパーティションに格納されていたデータが現在は集計形式でマテリアライズド・ビューに格納されていると、PCTリフレッシュではそのパーティションとマテリアライズド・ビューとの再同期化が試みられ、再計算できない履歴データが削除される可能性があるためです。

sales表に前年度のデータが格納されており、cust_mth_sales_mvには過去10年間のデータが集計形式で保持されているとします。

  1. sales表のパーティションから古いデータを削除します。

    ALTER TABLE sales TRUNCATE PARTITION month1;
    

    マテリアライズド・ビューは、パーティション操作によって失効とみなされ、リフレッシュが必要です。ただし、ディテール表にはパーティションに関連したすべてのデータが含まれていないため、高速リフレッシュは試行できません。

  2. そのため、マテリアライズド・ビューが最新のものであるとOracle Databaseが認識できるように、マテリアライズド・ビューを変更します。

    ALTER MATERIALIZED VIEW cust_mth_sales_mv CONSIDER FRESH;
    

    この文は、Oracle Databaseに対してcust_mth_sales_mvは意図した用途に使用できる最新のものであると通知します。ただし、マテリアライズド・ビューのステータスは、最新でも失効でもありません。かわりに、UNKNOWNになっています。マテリアライズド・ビューのクエリー・リライトがQUERY_REWRITE_INTEGRITY = stale_toleratedモードで使用可能になっている場合は、それがリライトに使用されます。

  3. データをsalesに挿入します。

  4. マテリアライズド・ビューをリフレッシュします。

    EXECUTE DBMS_MVIEW.REFRESH('CUST_MTH_SALES_MV', 'F', '', TRUE, FALSE,0,0,0,FALSE);
    

    高速リフレッシュでは、sales表に対してINSERT文のみが発生したことが検出されるため、このマテリアライズド・ビューは新規データで更新されます。ただし、マテリアライズド・ビューのステータスはUNKNOWNのままです。マテリアライズド・ビューをFRESHステータスに戻す唯一の方法は、完全リフレッシュを行うことです。これにより、マテリアライズド・ビューからも古いデータが削除されます。