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

この章では、データ・ウェアハウス環境でマテリアライズド・ビューを使用する際に良好なパフォーマンスおよびデータの整合性を維持する主要な要素である、マテリアライズド・ビューのリフレッシュ方法について説明します。

この章の内容は次のとおりです。

7.1 マテリアライズド・ビューのリフレッシュについて

データベースでは、実表の変更後にマテリアライズド・ビューをリフレッシュして、マテリアライズド・ビューのデータを管理します。

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

マテリアライズド・ビューのリフレッシュのタイプについて

次の3つの増分リフレッシュ方法があります。
  • ログベースのリフレッシュ
  • パーティション・チェンジ・トラッキング(PCT)リフレッシュ
  • 論理パーティション・チェンジ・トラッキング(LPCT)リフレッシュ

実表に対するパーティション・メンテナンス操作(PMOPS)がある場合、使用可能な増分リフレッシュ方法はPCTのみです。

増分リフレッシュは、一般にFASTリフレッシュと呼ばれます。これは、通常は完全リフレッシュよりも高速に実行されるためです。

完全リフレッシュは、マテリアライズド・ビューをBUILD IMMEDIATEで定義した場合に、最初に作成するときに実行されます。ただし、そのマテリアライズド・ビューが事前作成表を参照する場合、またはBUILD DEFERREDで定義された場合は除きます。ユーザーは、マテリアライズド・ビューを作成した後いつでも完全リフレッシュを実行できます。完全リフレッシュを実行すると、マテリアライズド・ビューを定義する問合せも実行されます。この処理は、特にデータベースが大量のデータを読み取って処理する必要がある場合に遅くなることがあります。

増分リフレッシュにより、マテリアライズ・ビューを最初から再作成する必要がなくなります。このように、変更のみを処理するため、リフレッシュ時間を大幅に削減できます。マテリアライズド・ビューは、必要時に、または定期的にリフレッシュできます。また、実表と同じデータベース内のマテリアライズド・ビューは、トランザクションによって実表の変更がコミットされるたびにリフレッシュできます。

ログベースの高速リフレッシュ方法を使用する場合、実表に対する変更はマテリアライズド・ビュー・ログまたはダイレクト・ローダー・ログに記録されます。マテリアライズド・ビュー・ログは、実表への変更を記録するスキーマ・オブジェクトであるため、実表で定義されているマテリアライズド・ビューを増分リフレッシュできます。マテリアライズド・ビュー・ログは、それぞれ1つの実表に関連付けられています。マテリアライズド・ビュー・ログは、実表と同じデータベースおよびスキーマに格納されます。

LPCTはPCTと似ていますが、LPCTには、実表に対する物理パーティション化ではなく論理パーティション化方法が必要です。PCT対応のマテリアライズド・ビューの場合と同様に、LPCT対応のマテリアライズド・ビューでは、リフレッシュ操作にマテリアライズド・ビュー・ログは必要ありません。マテリアライズド・ビューが定義されている実表は、キー範囲を使用して論理的にパーティション化されます。LPCTパーティション化キーを使用する表には物理パーティション化がないため、LPCTキー範囲に属する表の行は、別個の物理パーティションに分離されません。実表は、物理的にパーティション化しないか、論理パーティション・キーとは異なるキーで物理的にパーティション化することができます。

PCTリフレッシュ方法は、変更された実表がパーティション化されている場合に使用でき、変更された実表のパーティションを使用して、マテリアライズド・ビュー内の影響を受けるパーティションまたはデータの部分を識別することができます。この方法では、影響を受けるマテリアライズド・ビュー・パーティション内のすべてのデータ、またはデータのうちの影響を受ける部分が削除され、ゼロから再計算されます。

なお、表がすでに物理的にパーティション化されている場合は、LPCTを同じ物理パーティション化キーで定義できません。また、LPCTリフレッシュを再度使用するには、まず表に対するPMOPSで完全リフレッシュが必要になります。

マテリアライズド・ビューのリフレッシュ・モードについて

マテリアライズド・ビューを作成する場合、リフレッシュをON DEMANDで行うか、ON COMMITで行うかを指定できます。

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

ON COMMITの場合は、トランザクションがコミットされるたびに、マテリアライズド・ビューが変更されます。このため、マテリアライズド・ビューに常に最新データが含まれていることが保証されます。または、ON DEMANDを指定すると、マテリアライズド・ビューのリフレッシュが発生する時期を制御できます。ON DEMANDマテリアライズド・ビューの場合、リフレッシュはDBMS_SYNC_REFRESHパッケージまたはDBMS_MVIEWパッケージで提供されるリフレッシュ方法で実行できます。

  • DBMS_SYNC_REFRESHパッケージには、同期リフレッシュのAPIが含まれています。詳細は、同期リフレッシュを参照してください。

  • DBMS_MVIEWパッケージに含まれるAPIの使用方法については、この章で説明します。リフレッシュ操作の基本タイプには、完全リフレッシュ、高速リフレッシュ、パーティション・チェンジ・トラッキング(PCT)リフレッシュの3つがあります。

DBMS_MVIEWパッケージには、リフレッシュ操作を実行するための3つのAPIが含まれています。

  • DBMS_MVIEW.REFRESH

    1つまたは複数のマテリアライズド・ビューをリフレッシュします。

  • DBMS_MVIEW.REFRESH_ALL_MVIEWS

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

  • DBMS_MVIEW.REFRESH_DEPENDENT

    特定のプライマリ表またはマテリアライズド・ビュー、あるいはプライマリ表やマテリアライズド・ビューのリストに依存するマテリアライズド・ビューをすべてリフレッシュします。

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

これらの各リフレッシュ・オプションに対して、リフレッシュの実行方法に関する2つの技法、つまり、ホーム内リフレッシュとホーム外リフレッシュがあります。ホーム内リフレッシュは、マテリアライズド・ビューに対して直接リフレッシュ文を実行します。ホーム外リフレッシュは1つ以上の外部表を作成し、その外部表に対してリフレッシュ文を実行し、次にマテリアライズド・ビューまたは影響を受けるマテリアライズド・ビューのパーティションをその外部表で切り替えます。ホーム内リフレッシュとホーム外リフレッシュは両方とも、特定のリフレッシュ・シナリオで優れたパフォーマンスを発揮します。ただし、ホーム外リフレッシュを使用すると、リフレッシュ時、特にリフレッシュ文を完了するのに時間がかかる場合に、マテリアライズド・ビューの高可用性が実現されます。

同期リフレッシュと呼ばれるホーム外メカニズムは、ファクト表とそれらのマテリアライズド・ビューの両方が同じ方法でパーティション化されている場合、またはそれらのパーティションが機能依存性によって関連付けられている場合の、データ・ウェアハウスの一般的な使用シナリオを対象としています。

このリフレッシュ・アプローチにより、一連の表と表に定義されているマテリアライズド・ビューが、常に同期した状態を維持できます。このリフレッシュ方法では、ユーザーは、実表の内容を直接変更するのではなく、整合性を確保するために、実表とマテリアライズド・ビューに同時にこれらの変更を適用する、同期リフレッシュ・パッケージによって提供されるAPIを使用する必要があります。同期リフレッシュ方法は、増分データのロードが厳密に制御され、定期的に発生するデータ・ウェアハウスには非常に適しています。

7.1.1 マテリアライズド・ビューの完全リフレッシュについて

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

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

7.1.2 マテリアライズド・ビューの高速リフレッシュについて

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

7.1.3 マテリアライズド・ビューのパーティション・チェンジ・トラッキング(PCT)リフレッシュについて

パーティション・チェンジ・トラッキングは、マテリアライズド・ビューのより効率的なマテリアライズド・リフレッシュのために、マテリアライズド・ビューに含まれる表の個々のパーティション内の変更に関する知識を活用する機能です。

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

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

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

関連項目:

7.1.4 マテリアライズド・ビューの論理パーティション・チェンジ・トラッキング(LPCT)リフレッシュについて

論理パーティション・チェンジ・トラッキングは、マテリアライズド・ビューのより効率的なマテリアライズド・リフレッシュのために、マテリアライズド・ビューに含まれる表の個々の論理パーティション内の変更に関する知識を活用する機能です。表の物理パーティション化に依存するパーティション・チェンジ・トラッキングとは異なり、表の既存のパーティション化スキーマまたは存在しないパーティション化スキーマとは関係なく、表の論理パーティションを定義します。

LPCTでは、マテリアライズド・ビューの失効性を論理パーティションの粒度で追跡できるため、マテリアライズド・ビューの一部が失効している場合でも、クエリー・リライト・エンジンで、そのマテリアライズド・ビューの最新の論理パーティション内のデータを使用できます。その結果、それらのマテリアライズド・ビューはより使いやすくなります。実際の多くのアプリケーションでは、この結果、きめ細かなクエリー・リライトにより、問合せパフォーマンスが大幅に向上しています。LPCTでは、失効した論理パーティションのみを対象としてリフレッシュ操作を実行できます。これにより、データすべてが再ロードされることがなくなります。

LPCTを使用しない場合、非パーティション表にあるマテリアライズド・ビューは、完全に失効しているか完全に最新かのどちらかです。マテリアライズド・ビューが失効していると判断された場合、問合せで必要とされているデータが最新である可能性があっても、そのマテリアライズド・ビューはクエリー・リライトには使用できません。

LPCTの追跡メカニズムでは、指定されたLPCTキーに基づいて変更統計が記録され統合されます。隣接する変更データは、論理パーティションにグループ化されます。リフレッシュ中には、マテリアライズド・ビュー・ログが使用されるのではなく、LPCTによって論理パーティション内の変更点が調べられます。これらは、単一の列、およびRANGEまたはINTERVAL論理パーティションに限定されます。LPCTにより、実表のパーティション化が強制されることはありません。この機能では、新しいディクショナリ表にある定義済のRANGEまたはINTERVALパーティション内の変更点が追跡されます。LPCTリフレッシュを使用してマテリアライズド・ビューをリフレッシュするための構文は次のとおりです。

execute DBMS_MVIEW.REFRESH(<mview_name>,'L');

PCTとは異なり(これは表作成時に指定する必要がある)、LPCTは、表作成に関係なく、いつでも実表で作成、変更または削除できます。実表はパーティション化または非パーティション化できます。このため、PCTより適応性が高くなります。LPCTフレームワークでは、メタデータのみが必要であり、実表に対する変更はないため、PCTよりも物理的なオーバーヘッドが少なくなります。LPCTでは、PCTと組み合せることで、よりきめ細かく失効範囲を特定でき、より多くのクエリー・リライト、およびより高速なマテリアライズド・ビュー・リフレッシュが可能になります。実表が物理的にパーティション化されており、かつ別のパーティション化キーで定義されているLPCTも含む場合は、DBMS_MVIEW.REFRESH()のコールで'L'オプションを指定することで、LPCTとPCTを組み合せた方法を使用して依存マテリアライズド・ビューをリフレッシュできます。

トラッキングにおいては、LPCTにより実表にある変更された各行が記録されることはないため、LPCTはマテリアライズド・ビュー・ログよりも軽量になります。最新データのためにマテリアライズド・ビュー・ログ全体をスキャンし実表と結合する必要がないため、LPCTリフレッシュでは、特に、変更された行が比較的大きい場合には、ログベースの高速リフレッシュよりもパフォーマンスが高くなります。

論理パーティション・チェンジ・トラッキング(LPCT)では、変更された行が比較的大きい場合に、ログベースのリフレッシュのパフォーマンスがより高くなります。LPCTリフレッシュをログベースのリフレッシュと組み合せると、より的確な行が対象となることで効率がさらに向上します。

関連項目:

7.1.5 ホーム外リフレッシュ・オプションについて

Oracle Database 12cリリース1より、マテリアライズド・ビューのリフレッシュ・パフォーマンスおよび可用性を向上させる新しいリフレッシュ・オプションが利用可能となります。このリフレッシュ・オプションはホーム外リフレッシュと呼ばれます。これは、マテリアライズド・ビューのコンテナ表に直接変更を適用する既存のホーム内リフレッシュとは対照的に、リフレッシュの際に外部表を使用するためです。ホーム外リフレッシュ・オプションは、FAST ('F')、COMPLETE ('C')、PCT ('P')、FORCE ('?')など、既存のすべてのリフレッシュ方法とともに使用できます。ホーム外リフレッシュは特に、従来のDML文ではうまく対応できない大量のデータ変更を伴う状況を処理する際に効果的です。また、リフレッシュされるマテリアライズド・ビューは、リフレッシュ文の実行の際にダイレクト・アクセスおよびクエリー・リライトに使用できるため、非常に高い可用性を得ることができます。さらに、マテリアライズド・ビューのコンテナ表が徐々に断片化されたり、リフレッシュの中間結果が表示されるなどの問題の可能性を回避するのにも役立ちます。

ホーム外リフレッシュでは、マテリアライズド・ビューの全体または影響を受ける部分は、1つ以上の外部表に計算されます。パーティション化されたマテリアライズド・ビューの場合、パーティション・レベルのチェンジ・トラッキングが可能で、マテリアライズド・ビューにローカル索引が定義されていれば、ホーム外の方法では外部表にも同じローカル索引が構築されます。このリフレッシュ・プロセスは、マテリアライズド・ビューと外部表の切替え、または影響を受けるパーティションと外部表とのパーティション交換により行われます。切替えまたはパーティション交換操作中にクエリー・リライトがサポートされないことに注意してください。リフレッシュの間、外部表には効率的なダイレクト・ロードによって移入が行われます。

この項では、次の項目について説明します。

7.1.5.1 ホーム外リフレッシュのタイプ

ホーム外リフレッシュには次の3つのタイプがあります。

  • ホーム外高速リフレッシュ

    これは、ホーム内高速リフレッシュより高い可用性を提供します。また、変更がマテリアライズド・ビューの多くの部分に影響を与える場合には、より良好なパフォーマンスが得られます。

  • ホーム外PCTリフレッシュ

    これは、ホーム内PCTリフレッシュより高い可用性を提供します。パーティション化されたマテリアライズド・ビューおよびパーティション化されていないマテリアライズド・ビューには、2つの異なるアプローチがあります。切捨ておよびダイレクト・ロードが実現可能ではない場合、変更が比較的大規模であればホーム外リフレッシュを使用する必要があります。切捨ておよびダイレクト・ロードが実現可能な場合、パフォーマンスの観点からは、ホーム内リフレッシュをお薦めします。可用性の観点からは、望ましいのは常にホーム外リフレッシュです。

  • ホーム外完全リフレッシュ

    これは、ホーム内完全リフレッシュより高い可用性を提供します。

DBMS_MVIEWパッケージのリフレッシュ・インタフェースをmethod = ?およびout_of_place = trueと指定して使用すると、まずホーム外高速リフレッシュが試みられ、次にホーム外PCTリフレッシュ、最後にホーム外完全リフレッシュが試みられます。次に例を示します。

DBMS_MVIEW.REFRESH('CAL_MONTH_SALES_MV', method => '?', 
   atomic_refresh => FALSE, out_of_place => TRUE);
7.1.5.2 ホーム外リフレッシュの制限および考慮事項

ホーム外リフレッシュには、対応するホーム内リフレッシュを使用する場合に適用されるすべての制限が適用されます。また、これには、次の制限があります。

  • マテリアライズド結合ビューおよびマテリアライズド集計ビューのみが使用可能です。

  • ON COMMITリフレッシュは使用できません。

  • リモート・マテリアライズド・ビュー、キューブ・マテリアライズド・ビュー、オブジェクト・マテリアライズド・ビューは使用できません。

  • LOB列は使用できません。

  • マテリアライズド・ビューでマテリアライズド・ビューのログ、トリガーまたは制約(NOT NULLを除く)が定義されている場合、使用できません。

  • マテリアライズド・ビューがCLUSTERING句を含む場合、使用できません。

  • マテリアライズド・ビューにセキュリティ・ポリシーが定義されている場合、許可されません。

  • CREATEまたはALTER MATERIALIZED VIEWセッション、またはALTER TABLEセッション内の完全リフレッシュには適用されません。

  • アトミック・モードは使用できません。atomic_refreshTRUEに指定し、out_of_placeTRUEに指定すると、エラーが表示されます。

ホーム外PCTリフレッシュには、次の制限があります。

  • UNION ALLやグルーピング・セットは使用できません。

ホーム外高速リフレッシュには、次の制限があります。

  • UNION ALL、グルーピング・セットおよび外部結合は使用できません。

  • 複数の表が複合DML文で変更されている場合、マテリアライズド結合ビューでは使用できません。

ホーム外リフレッシュでは、リフレッシュの間の外部表および索引用に追加の記憶域が必要です。したがって、使用可能な表領域が十分にあるか、自動拡張がオンになっている必要があります。

ホーム外PCTリフレッシュのパーティション交換は、マテリアライズド・ビューのグローバル索引に影響を及ぼします。したがって、マテリアライズド・ビューのコンテナ表にグローバル索引が定義されている場合、Oracleでは、パーティション交換の前にグローバル索引を無効にし、パーティション交換の後でグローバル索引を再構築します。この再構築はさらなるオーバーヘッドとなります。

7.1.6 マテリアライズド・ビューのON COMMITリフレッシュについて

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

7.1.7 マテリアライズド・ビューのON STATEMENTリフレッシュについて

ON STATEMENTリフレッシュ・モードを使用するマテリアライズド・ビューは、マテリアライズド・ビューの実表のいずれかに対してDML操作が実行されるたびに自動的にリフレッシュされます。

ON STATEMENTリフレッシュ・モードを使用すると、実表が変更された場合、マテリアライズド・ビューにすぐに反映されます。トランザクションをコミットしたり、マテリアライズド・ビュー・ログを実表に保持する必要はありません。DML文が後でロールバックされた場合、マテリアライズド・ビューに加えられた対応する変更もロールバックされます。

ON STATEMENTリフレッシュ・モードを使用するには、マテリアライズド・ビューが高速リフレッシュ可能である必要があります。高速リフレッシュのパフォーマンスを向上させるために、ファクト表のROWID列に索引が自動的に作成されます。

ON STATEMENTリフレッシュ・モードの利点は、マテリアライズド・ビュー・ログを保持するというオーバーヘッドを伴うことなく、マテリアライズド・ビューが実表内のデータと常に同期される点です。ただし、このモードでは、DML操作の一環としてマテリアライズド・ビューがリフレッシュされるため、DML操作の実行に要する時間が長くなることがあります。

関連項目:

ON STATEMENT句の制限については、『Oracle Database SQL言語リファレンス』を参照してください

例7-1 ON STATEMENTリフレッシュを使用するマテリアライズド・ビューの作成

この例では、ON STATEMENTリフレッシュ・モードを使用し、sh.salessh.customersおよびsh.productsの各表に基づくマテリアライズド・ビューsales_mv_onstatを作成します。実表のいずれかに対してDML操作が実行されると、マテリアライズド・ビューは自動的にリフレッシュされます。マテリアライズド・ビューをリフレッシュするために、DML操作の後にコミットは必要ありません。

CREATE MATERIALIZED VIEW sales_mv_onstat
REFRESH FAST ON STATEMENT USING TRUSTED CONSTRAINT
AS
SELECT s.rowid sales_rid, c.cust_first_name first_name, c.cust_last_name last_name,
       p.prod_name prod_name, 
    s.quantity_sold quantity_sold, s.amount_sold amount_sold
FROM sh.sales s, sh.customers c, sh.products p
WHERE s.cust_id = c.cust_id and s.prod_id = p.prod_id;

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

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

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

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

COMPLETE

C

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

FAST

F

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

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

FAST_PCT

P

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

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

FORCE

?

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

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

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

関連項目:

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

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

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

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

  • リフレッシュ方法: F-Fast、P-Fast_PCT、L-FAST_LPCT、?-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に設定されている場合にクエリー・リライトを使用できます。リフレッシュがネステッド・ビューで実行される場合は、アトミック・リフレッシュは保証されません。

  • ホーム外リフレッシュを使用するかどうか

    このパラメータは、既存のすべてのリフレッシュ方法(FPC?)とともに使用できます。したがって、Fout_of_place = trueを指定すると、ホーム外高速リフレッシュが試みられます。同様に、Pout_of_place = trueを指定すると、ホーム外PCTリフレッシュが試みられます。

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

DBMS_MVIEW.REFRESH('CAL_MONTH_SALES_MV', 'F', '', TRUE, FALSE, 0,0,0, 
   FALSE, 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, FALSE);

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

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

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

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

  • 失敗数(OUT変数)

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

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

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

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

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

  • ホーム外リフレッシュを使用するかどうか

    このパラメータは、既存のすべてのリフレッシュ方法(FPC?)とともに使用できます。したがって、Fout_of_place = trueを指定すると、ホーム外高速リフレッシュが試みられます。同様に、Pout_of_place = trueを指定すると、ホーム外PCTリフレッシュが試みられます。

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

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

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

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

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

  • 失敗数(OUT変数)

  • 依存する表

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

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

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

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

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

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

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

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

  • ホーム外リフレッシュを使用するかどうか

    このパラメータは、既存のすべてのリフレッシュ方法(FPC?)とともに使用できます。したがって、Fout_of_place = trueを指定すると、ホーム外高速リフレッシュが試みられます。同様に、Pout_of_place = trueを指定すると、ホーム外PCTリフレッシュが試みられます。

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

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

7.1.12 リフレッシュへのジョブ・キューの使用について

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

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

関連項目:

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

すべてのマテリアライズド・ビューの高速リフレッシュが可能であるとは限りません。したがって、パッケージDBMS_MVIEW.EXPLAIN_MVIEWを使用して、マテリアライズド・ビューに使用可能なリフレッシュ方法を判断します。

マテリアライズド・ビューを高速リフレッシュできるようにする方法がわからない場合は、DBMS_ADVISOR.TUNE_MVIEWプロシージャを使用して、高速リフレッシュできるマテリアライズド・ビューの作成に必要な文を含むスクリプトを指定します。

関連項目:

7.1.14 近似問合せに基づいたマテリアライズド・ビューのリフレッシュ

Oracle Databaseは、近似問合せを使用して定義されているマテリアライズド・ビューの高速リフレッシュを実行します。

近似問合せには、近似結果を返すSQL関数が含まれます。近似問合せを含むマテリアライズド・ビューのリフレッシュは、マテリアライズド・ビューの実表で実行されるDML操作によって異なります。

  • 挿入操作の場合は、詳細パーセンタイルを含むマテリアライズド・ビューに対して高速リフレッシュが使用されます。

  • 削除操作または削除につながるDML操作(UPDATEMERGEなど)の場合は、マテリアライズド・ビューにWHERE句が含まれない場合のみ、近似集計を含むマテリアライズド・ビューに対して高速リフレッシュが使用されます。

マテリアライズド・ビュー・ログは、高速リフレッシュを必要とするマテリアライズド・ビューのすべての実表に存在する必要があります。
  • 近似問合せに基づいたマテリアライズド・ビューをリフレッシュするには:

    DBMS_REFRESH.REFRESHプロシージャを実行して、マテリアライズド・ビューの高速リフレッシュを実行します。

例7-2 近似問合せに基づいたマテリアライズド・ビューのリフレッシュ

次の例では、近似問合せに基づいたマテリアライズド・ビューpercentile_per_pdtの高速リフレッシュを実行します。

exec DBMS_MVIEW.REFRESH('percentile_per_pdt', method => 'F');

7.1.15 コミット時のマテリアライズド・ビューの同時リフレッシュについて

Oracle Database 23ai以降では、コミット時の複数のマテリアライズド・ビューを同時にリフレッシュできます。

マテリアライズド・ビューの同時リフレッシュは、複数のセッションで同一のコミット時のアトミック・マテリアライズド・ビューを同時にリフレッシュできることを意味します。

同時リフレッシュが有効になっている場合、実表に対してDMLを実行する複数のセッションで、マテリアライズド・ビューを同時にリフレッシュできます。同時セッションの数に制限はありません。

同時リフレッシュが無効になっている場合、マテリアライズド・ビューのリフレッシュはシリアライズされます。この場合、複数のセッションでマテリアライズド・ビューを同時にリフレッシュすることはできません。マテリアライズド・ビューを更新できるのは、一度に1つのリフレッシュ・セッションのみです。現在のセッションが完了するまで、その他のリフレッシュはブロックされます。その後、次のセッションを続行できます。

コミット時のマテリアライズド・ビューの同時リフレッシュに最適なユース・ケース

この機能は、OLTPでコミット時のマテリアライズド・ビューのリフレッシュを実行する場合や、多数の同時DMLトランザクションによってファクト表のみが更新される場合に便利です。

コミット時のマテリアライズド・ビューの同時リフレッシュの有効化

マテリアライズド・ビューの同時リフレッシュは、デフォルトでは無効になっています。CREATE MATERIALIZED VIEWまたはALTER MATERIALIZED VIEW文で同時リフレッシュを有効または無効にできます。
{ ENABLE | DISABLE } CONCURRENT REFRESH

次に例を示します。

CREATE MATERIALIZED VIEW "T1"."MV1" ("C1", "C2")
  SEGMENT CREATION DEFERRED
  REFRESH FAST ON COMMIT
  WITH PRIMARY KEY USING DEFAULT LOCAL ROLLBACK SEGMENT
  USING ENFORCED CONSTRAINTS DISABLE ON QUERY COMPUTATION DISABLE QUERY REWRITE
ENABLE CONCURRENT REFRESH
  AS SELECT "TB1"."C1" "C1","TB1"."C2" "C2" FROM "TB1" "TB1

コミット時のマテリアライズド・ビューの同時リフレッシュが許可される条件

次の条件によって、同時リフレッシュを続行できるかどうかが決まります。
  • 同時リフレッシュが有効になっている。(有効にできるのは、コミット時のマテリアライズド・ビューのリフレッシュのみです。)
  • すべての同時DMLセッションで同じ実表が更新される。
  • 異なるリフレッシュ・セッションで更新されたマテリアライズド・ビュー行が重複しない。

制限事項

マテリアライズド・ビューDDLのコミット時の高速リフレッシュでは、同時リフレッシュを有効にできません。同時リフレッシュを有効にできるのは、コミット時のマテリアライズド・ビューのみです。

コミット時のマテリアライズド・ビューの同時リフレッシュが有効かどうかを判断する方法

ビューALL_MVIEWSをチェックして、同時リフレッシュが有効かどうかなど、マテリアライズド・ビューのすべてのプロパティを表示できます。

関連項目:

Oracle Database SQL言語リファレンスCREATE MATERIALIZED VIEW文の説明では、{ ENABLE | DISABLE } CONCURRENT REFRESHの完全なコンテキストが示されています。

DBMS_MVIEW_REFRESHおよびデータベースPL/SQLパッケージおよびタイプ・リファレンスのマテリアライズド・ビューのリフレッシュに関連するその他のAPIを参照してください。

7.1.16 表のオンライン再定義中に依存マテリアライズド・ビューをリフレッシュする方法について

DBMS_REDEFINITIONパッケージを使用して表のオンライン再定義を実行しているときに、再定義されている表に依存する高速リフレッシュ可能なマテリアライズド・ビューの増分リフレッシュを実行できます。

Oracle Database 12cリリース2 (12.2)より前は、再定義が実行されている表の依存マテリアライズド・ビューをリフレッシュするには、再定義処理が完了した後に完全なリフレッシュを手動で実行する必要がありました。

表のオンライン再定義中に、依存マテリアライズド・ビューを増分リフレッシュするには、DBMS_REDEFINITON.REDEF_TABLEプロシージャのrefresh_dep_mviewsパラメータにYを設定します。表のオンライン再定義中に依存マテリアライズド・ビューをリフレッシュできるのは、マテリアライズド・ビューが高速リフレッシュ可能で、ROWIDベースのマテリアライズド・ビューまたはマテリアライズド結合ビューではない場合のみです。これらの制限に従っていないマテリアライズド・ビューはリフレッシュされません。

次の依存マテリアライズド・ビューを持つmy_sales表について考えてみます。

  • my_sales_pk_mv: 高速リフレッシュ可能で主キーベースのマテリアライズド・ビュー

  • my_sales_rid_mv: 高速リフレッシュ可能でROWIDベースのマテリアライズド・ビュー

  • my_sales_mjv: 高速リフレッシュ可能なマテリアライズド結合ビュー

  • my_sales_mav: 高速リフレッシュ可能なマテリアライズド集計ビュー

  • my_sales_rmv: 完全リフレッシュのみが可能なマテリアライズド・ビュー

次のコマンドを実行した場合、高速リフレッシュはmy_sales_pk_mvおよびmy_sales_mavマテリアライズド・ビューでのみ実行されます。

DBMS_REDEFINITION.REDEF_TABLE(
uname => 'SH',
tname => 'MY_SALES',
table_compression_type => 'ROW STORE COMPRESS ADVANCED',
refresh_dep_mviews => 'Y');

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

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

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

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

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

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

7.1.18 リフレッシュの監視

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

SELECT * FROM V$SESSION_LONGOPS;

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

SELECT * FROM DBA_JOBS_RUNNING;

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

これらは、表のパーティションの状態を確認し、マテリアライズド・ビューのデータの最新または失効の範囲を判別できるビューです。

  • *_MVIEWS

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

  • *_MVIEW_DETAIL_RELATIONS

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

  • *_MVIEW_DETAIL_PARTITION

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

  • *_MVIEW_DETAIL_SUBPARTITION

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

  • *_MVIEW_DETAIL_LOGICAL_PARTITIONS

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

物理パーティションが最新であるかどうか確認

パーティション・チェンジ・トラッキング(PCT)を使用して、物理パーティションが最新であるかどうかを確認できます。失効したパーティションがあるインスタンスを次に示します。

PCTの最新状態

パーティションの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

論理パーティションが最新であるかどうか確認

論理パーティション・チェンジ・トラッキング(LPCT)を使用して、論理パーティションの失効/最新状態を判断します。

この例では、論理パーティションはLP1、LP2、LP3およびLP4です。LP3が失効していると仮定します。

LPCTの最新状態

ノート:

論理パーティション化では、サブパーティションはサポートされていません。

DBA_MVIEW_DETAIL_LOGICAL_PARTITIONを問い合せて、論理パーティションが最新であるかどうか判断できます。

SQL> SELECT MVIEW_NAME, DETAILOBJ_NAME, LPARTNAME, LPART#, FRESHNESS \
FROM DBA_MVIEW_DETAIL_LOGICAL_PARTITION WHERE MVIEW_NAME = 'MV1' ORDER BY 1,2,3,4;

MVIEW_NAME            DETAILOBJ_NAME       LPARTNAME       LPART#    FRESHNESS
----------------------------------–-------------------------------------------
       MV1                   SALES             LP1            1        FRESH 
       MV1                   SALES             LP2            2        FRESH
       MV1                   SALES             LP3            3        STALE
       MV1                   SALES             LP4            4        FRESH

関連項目:

詳細および例は、最新状態の判別に使用するビューの使用例を参照してください。

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

次に、マテリアライズド・ビューおよびそのディテール表のパーティション最新状態の情報の表示方法を示す例を示します。

例7-3 マテリアライズド・ビューの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

例7-4 マテリアライズド・ビューのディテール表における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

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

サブパーティションの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

7.1.20 マテリアライズド・ビューのリフレッシュのスケジュール

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

このような場合、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パッケージのいずれかのリフレッシュ・プロシージャに渡すことは有益です。これによって、プロシージャは、マテリアライズド・ビューに対してリフレッシュを実行する順序を認識できます。

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

この項の内容は次のとおりで、マテリアライズド・ビューのリフレッシュのヒントを含みます。

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

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

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

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

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

  • Oracleのバルク・ロード・ユーティリティまたはダイレクト・パス・インサート(ロードに対するAPPENDヒント付きのINSERT)を使用します。Oracle Database 12cより、データベースではバルク・ロード操作の一部として(CTASおよびIAS)、索引の作成時の統計の収集方法に似た表統計の自動収集を行います。データ・ロードの際に統計を収集することによって、スキャン操作の追加を回避し、ユーザーがデータを使用できるようになるとすぐに必要な統計を提供できます。

    これは、従来の挿入に比べてはるかに効率的です。ロード中はすべての制約を使用禁止にし、ロード終了後に使用可能に戻します。ダイレクト・ロードと従来型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によってスケジューリングされます。

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

結合を含み、集計を含まないマテリアライズド・ビューは、集計を含むマテリアライズド・ビューよりもかなりサイズが大きくなる傾向があるため、ディテール表の結合列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. マテリアライズド・ビューをリフレッシュします。

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

ネステッド・マテリアライズド・ビューのベースとなるオブジェクトは、マテリアライズド・ビューのリフレッシュ時にはすべて通常の表として扱われます。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で、あるオブジェクトに直接依存するマテリアライズド・ビューのリストが作成されます。

7.2.4 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に対して別個の値を持ちます。

7.2.5 コミット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)が発生し、これらのマテリアライズド・ビュー・ログが高速リフレッシュに関して相互に互換性がないことを示すメッセージが表示されます。

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

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

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

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

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

パーティション・チェンジ・トラッキングによるマテリアライズド・ビューの高速リフレッシュでは、PCTリフレッシュに関する追加情報が提供されています。

7.3.1 パーティション・チェンジ・トラッキングによるマテリアライズド・ビューの高速リフレッシュ

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

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

この機能の使用例を次に示します。

7.3.1.1 マテリアライズド・ビューのPCT高速リフレッシュ: 使用例1

この使用例では、salestime_id列を使用してパーティション化された表で、productsprod_category列でパーティション化されています。表timesはパーティション表ではありません。

  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;
7.3.1.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, FALSE);
    ORA-12052: cannot fast refresh materialized view SH.CUST_MTH_SALES_MV
    

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

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

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

7.3.1.3 マテリアライズド・ビューの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, FALSE);
    

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

7.4 ハイブリッド・パーティション表に基づくマテリアライズド・ビューのリフレッシュ

ハイブリッド・パーティション表に基づくマテリアライズド・ビューをリフレッシュするには、完全リフレッシュ方法、高速リフレッシュ方法またはPCTリフレッシュ方法を使用できます。

Oracle Databaseでは外部ソースでのデータのメンテナンス方法を制御できないため、外部パーティションのデータが最新であることは保証されず、その最新状態はUNKNOWNとマークされます。外部パーティションのデータは、信頼できる整合性モードまたは失効許可モードでのみ使用できます。

外部パーティションから発生するデータのリフレッシュは、コストが高くなり、多くの場合は不要な操作となる(ソース・データが変更されていない場合)可能性があります。DBMS_MVIEW.REFRESHプロシージャのskip_ext_data属性を使用して、外部パーティションに対応するマテリアライズド・ビュー・データのリフレッシュをスキップできます。この属性をTRUEに設定すると、外部パーティションに対応するマテリアライズド・ビュー・データは再計算されず、状態がUNKNOWNの信頼できるモードのままになります。デフォルトでは、skip_ext_dataはFALSEです。

ノート:

マテリアライズド・ビューの基礎となるハイブリッド・パーティション表でPCTが有効化されていない場合、サポートされるリフレッシュ方法はCOMPLETEおよびFORCEのみです。FASTリフレッシュはサポートされません。

例7-6 ハイブリッド・パーティション表に基づくマテリアライズド・ビューのリフレッシュ

マテリアライズド・ビューhypt_mvの内部パーティションyear_2020が失効していると仮定します。このマテリアライズド・ビューは、ハイブリッド・パーティション表に基づいています。カタログ・ビューUSER_MVIEW_DETAIL_PARTITIONを問い合せると、次のように表示されます。

SELECT mview_name, detail_partition_name, freshness, last_refresh_time 
	FROM USER_MVIEW_DETAIL_PARTITION;

MVIEW_NAME	DETAIL_PARTITION_NAME	FRESHNESS	LAST_REFRESH_TIME
----------       ---------------------	---------	-----------------
HyPT_MV          century_19		    UNKNOWN          2018-10-31 20:48:00.20
HyPT_MV          century_20                  UNKNOWN          2018-10-31 20:48:00.20
HyPT_MV          year_2020		     STALE	     2018-10-31 20:48:00.20
HyPT_MV          year_2021                   FRESH            2021-10-31 20:48:00.20

次のコマンドを使用して、マテリアライズド・ビューの高速リフレッシュを実行します。

DBMS_MVIEW.REFERSH('HyPT_MV', 'F', skip_ext_data => false);

リフレッシュ後にカタログ・ビューUSER_MVIEW_DETAIL_PARTITIONを問い合せると、次のように表示されます。

SELECT mview_name, detail_partition_name, freshness, last_refresh_time 
	FROM USER_MVIEW_DETAIL_PARTITION;

MVIEW_NAME     DETAIL_PARTITION_NAME    FRESHNESS      LAST_REFRESH_TIME
----------     ---------------------    ---------      -----------------
HyPT_MV        century_19               UNKNOWN        2018-10-31 20:48:00.20
HyPT_MV        century_20               UNKNOWN        2018-10-31 20:48:00.20
HyPT_MV        year_2020                FRESH          2021-10-31 21:32:17.00
HyPT_MV        year_2021                FRESH          2021-10-31 20:48:00.20


内部パーティションyear_2020のみがリフレッシュされています。パーティションyear_2021は、すでに最新であるためリフレッシュされませんでした。skip_ext_dataがFALSEに設定されている場合、外部パーティションの完全リフレッシュおよび内部パーティションの高速リフレッシュが実行されます。

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

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操作はすぐに処理を終了します。

    同期リフレッシュを使用する場合は、ステップ3を実行するかわりに、DBMS_SYNC_REFRESH.REGISTER_PARTITION_OPERATIONパッケージを使用してsales_01_2001表を登録する必要があります。詳細は、同期リフレッシュを参照してください。

このパーティション化テクニックには、重要な利点があります。第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つ以上の圧縮パーティションがすでにパーティション表の一部に含まれていることも想定されます。

関連項目:

7.5.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つのパーティションを削除したためです。使用が制限される時間は、表を交換するための時間とほぼ同程度になります。グローバル索引の有無およびその数によって、この時間枠は変わります。既存のグローバル索引がない場合、この時間枠はほんの数秒です。

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

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

関連項目:

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

この項では、リフレッシュとともにパーティション化が使用される次の2つの典型的なシナリオについて説明します。

7.5.2.1 データ・ウェアハウスのリフレッシュのためのパーティション化: 使用例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操作を使用します。この方法を使用するのは、索引をメンテナンスするよりも、削除して再作成する方が効率的な場合です。

7.5.2.2 データ・ウェアハウスのリフレッシュのためのパーティション化: 使用例2

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

解決策 1

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

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

解決策2

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

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

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

7.6.1 効率的な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文で実行できます。

例7-7 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操作で行を削除する。

例7-8 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

例7-9 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句を省略した場合は、ソース表とターゲット表に対してアンチ結合が実行されます。これによって、ソース表とターゲット表がより効率的に結合されます。

例7-10 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操作がどのようにスキップされるかを示します。条件の述語は、ターゲット表とソース表の両方を指すことができます。

例7-11 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が実行されることを示します。条件の述語は、ソース表のみを指すことができます。条件の述語は、ソース表のみを指すことができます。

例7-12 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句の条件の下で結合を実行しない場合は削除されません。

例7-13 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)

7.6.2 データ・ウェアハウスの参照整合性の維持

データ・ウェアハウス環境によっては、参照整合性を保証するために新しいデータを表に挿入する必要がある場合もあります。たとえば、キャッシュ・レジスタから直接データを取り出す業務系システムから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));

7.6.3 データ・ウェアハウスからのデータのパージ

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

ただし、それ以外の場合でも、データをデータ・ウェアハウスから削除する必要がある場合があります。たとえば、ある小売会社が、以前に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表の各パーティションに対して、このプロセスを繰り返します。