もしGoldenGateに、DBAやデータエンジニアが愛憎相半ばするパラメータがあるとすれば、HANDLECOLLISIONSは間違いなくその筆頭に挙げられるでしょう。本番環境のReplicatプロセスがORA-00001: unique constraint violatedエラーで異常終了(Abend)し、データ同期が中断、ビジネスに緊急事態が発生します。この時、一見単純なHANDLECOLLISIONSパラメータがプロセスを「生き返らせる」ことができますが、その代償は想像をはるかに超えるかもしれません。

本記事では、その動作原理を深く掘り下げ、様々なシナリオでの利点と欠点を分析し、明確な意思決定のフレームワークを提供します。読了後、いつ使用すべきか、いつ避けるべきかを自信を持って判断できるようになり、データの一貫性を保証するより良い代替手段を選択できるようになるでしょう。

1. 競合の根本原因:

ReplicatのABENDはあくまで症状に過ぎず、その背後には実際のデータ競合が存在します。

  • INSERT 競合: Replicatがターゲットテーブルに行を挿入しようとしますが、同じ主キーまたは一意キーを持つ行が既に存在します。これは通常、データベースがORA-00001(Oracle)または類似の一意性制約エラーをスローする原因となります。
  • UPDATE 競合: Replicatが行を更新しようとしますが、主キーに基づいてターゲットテーブルでその行を見つけることができません。
  • DELETE 競合: Replicatが行を削除しようとしますが、同様にターゲットテーブルでその行を見つけることができません。

Oracleでは、後の2つの状況は通常ORA-01403: no data foundエラーを引き起こし、ReplicatをAbendさせます。

では、これらの競合はどこから来るのでしょうか?私のプロジェクト経験に基づくと、根本原因は通常以下のいずれかです。

  1. 初期ロードと増分同期の「ギャップ」: これが最も一般的な原因です。expdp/impdp、RMAN、またはOGGなどのツールを使用して初期ロードを完了し、その後Extract/Replicatを起動して増分同期を行う際、増分キャプチャの開始点(CSN/LSN)が初期ロードのデータスナップショット点と完全に一致していない場合、この「ギャップ」または「重複」内のデータが競合を引き起こします。
  2. ターゲット側が「クリーン」でない: ターゲットデータベースは純粋な読み取り専用のレプリカではありません。他のアプリケーション、バッチジョブ、あるいはDBAの手動操作がターゲット側でデータを挿入、変更、または削除しており、ソース側とターゲット側のデータのミラー関係を破壊しています。
  3. 双方向またはActive-Activeレプリケーション: Active-Activeアーキテクチャでは、競合は設計上考慮すべき要素です。A側とB側が同時に同じ主キーを持つデータを挿入する可能性があります。これらの操作が相手側にレプリケートされると、必然的にINSERT競合が発生します。
  4. ソース側でのログに記録されない操作: 例えば、OracleでNOLOGGINGまたはUNRECOVERABLEオプション付きの操作を実行したり、TRUNCATE TABLEコマンドを使用したりした場合(OGGはTRUNCATEをサポートできますが、不適切な設定は問題を引き起こす可能性があります)。これらの操作はExtractプロセスによって完全にキャプチャされない可能性があり、ソース側とターゲット側の状態の不一致につながります。

これらの根本原因を理解すれば、Replicatに単にこれらのエラーを「無視」させることが根本的な問題を解決しないことがわかるでしょう。

2. HANDLECOLLISIONSについて

それでは、HANDLECOLLISIONSについて紹介します。Replicatパラメータファイルにこれを追加すると、前述の競合を処理するデフォルトの動作が変更されます。

動作原理

HANDLECOLLISIONSのロジックは非常に直接的です。

  • INSERT競合に遭遇した場合(ターゲットにレコードが既に存在する): プロセスをAbendさせる代わりに、このINSERT操作を強制的にUPDATE操作に変換します。トレイルファイル内のレコードのすべての列値を使用して、ターゲットテーブル内の同じ主キーを持つ既存のレコードを上書きします。
  • UPDATEまたはDELETE競合に遭遇した場合(ターゲットにレコードが存在しない): これもAbendさせません。代わりに、このUPDATEまたはDELETE操作を静かに無視(破棄)し、何事もなかったかのように次のレコードの処理に進みます。

重要なポイント: HANDLECOLLISIONSの唯一の目的は、Replicatプロセスの継続性を保証することであり、データの絶対的な一貫性を保証するものではありません。それは「上書き」と「無視」という戦略を用いてエラーを回避し、データフローを継続させます。

潜在的なリスク

このメカニズムのリスクは明らかです。次のようなシナリオを考えてみましょう。

  1. ソース側: UPDATE table SET status='A' WHERE id=1;
  2. ターゲット側: 何らかの理由で、id=1のレコードが誤って削除されました。
  3. Replicatがこの更新を適用しようとすると、「no data found」競合に遭遇します。
  4. HANDLECOLLISIONSが有効になっている場合、このUPDATE操作は静かに破棄されます
  5. 結果: ソース側ではid=1のレコードのstatusは’A’ですが、ターゲット側ではそのレコード自体が存在しません。ここにデータ不整合が生まれ、OGGのどのレポートもこの「無視」イベントを通知しません。

3.HANDLECOLLISIONSの正しい使い方

リスクは多いものの、特定のシナリオではHANDLECOLLISIONSは依然として有効なツールです。以下に、OGG 19c/21cでそれを設定する方法を示します。

構文と例

HANDLECOLLISIONSは、グローバルとテーブル固有の2つのレベルで設定できます。影響範囲を最小限に抑えるため、常にテーブルレベルの設定を優先することを強く推奨します。

誤った例:グローバル設定(非推奨)

-- rep01.prm
-- これはすべてのテーブルに適用されるため、リスクが非常に高く、推奨されない設定です
REPLICAT rep01
USERIDALIAS ogg_tgt DOMAIN OracleGoldenGate
HANDLECOLLISIONS
MAP sales.customers, TARGET sales.customers;
MAP sales.orders, TARGET sales.orders;
MAP hr.employees, TARGET hr.employees;

正しい例:テーブルレベル設定(推奨)

初期化段階でデータ不整合の可能性があることがわかっているsales.ordersテーブルに対してのみ競合を処理したいとします。

-- rep01.prm
-- これはリスクを既知のテーブルに限定する、より安全な設定です
REPLICAT rep01
USERIDALIAS ogg_tgt DOMAIN OracleGoldenGate

-- ordersテーブルに対して競合処理を有効にする
MAP sales.orders, TARGET sales.orders, HANDLECOLLISIONS;

-- 他のテーブルは有効にしない。いかなる競合もAbendを引き起こし、問題を迅速に検出できる
MAP sales.customers, TARGET sales.customers;
MAP hr.employees, TARGET hr.employees;

MAPステートメントに, HANDLECOLLISIONSを追加することで、その適用範囲をsales.ordersテーブルに正確に限定します。customersテーブルやemployeesテーブルでは、いかなる競合も通常通りAbendを引き起こします。これこそが我々が望むこと、つまり未知の問題を明らかにすることです。

図解:HANDLECOLLISIONSのワークフロー

Oracle GoldenGate Handlecollisions Flow Chart

4. HANDLECOLLISIONS を使うべきとき、そしてより良い代替策

ここからが最も重要な部分です:果たして本当にこれを使うべきでしょうか?

HANDLECOLLISIONSの合理的な使用シナリオ

  1. 一時的な問題解決: 本番のReplicatが予期せず停止し、ビジネスへの影響が大きく、短時間でデータの問題を特定・修正できない場合。一時的にHANDLECOLLISIONSを追加してプロセスを稼働させることができますが、必ず以下の条件を守ってください
    • 問題のあるテーブルに対してのみ有効にする。
    • 直ちにチケットを作成し、DBAまたはデータエンジニアに根本原因の調査を依頼する。
    • 問題が解決したら、このパラメータを必ず削除する
  2. 一回限りのデータ同期または移行: データ移行や新しい災害復旧データベースを構築する際、ソースとターゲット間に軽微な差異があることがわかっており、ビジネス要件としてソースを絶対的な正とする場合。HANDLECOLLISIONSを使用して強制的に上書きし、迅速にデータを整合させることができます。同期が安定したら、削除を検討すべきです。

  3. 双方向/Active-Activeアーキテクチャ: これがHANDLECOLLISIONSの最も正当な使用場面です。Active-Active環境では、競合は予期された動作です。それでも、HANDLECOLLISIONSは競合検出・解決(CDR)メカニズムの一部に過ぎません。通常、「最終更新者が勝つ」ルールを保証したり、より複雑なビジネスロジックを実装したりするために、GETAPPLOPSUSEMAXなどの他のパラメータやカスタムの競合解決ロジックと組み合わせる必要があり、単純に上書きするだけではありません。

より良い代替案:REPERRORによる精密な制御

単一方向レプリケーションのシナリオの大多数において、特定の、既知で、許容可能なエラーを無視したい場合、私はREPERRORパラメータの使用をはるかに好みます。

REPERRORは、特定のデータベースエラーコードに対して、具体的なアクション(ABENDDISCARDRETRYなど)を定義することができます。

** HANDLECOLLISIONS vs. REPERROR**

特徴 HANDLECOLLISIONS REPERROR
粒度 粗粒度、固定の競合タイプを処理 細粒度、任意のデータベースエラーコードを対象可能
動作 固定:「InsertをUpdateに」、「Update/Deleteを無視」 カスタマイズ可能なアクション(DISCARDABENDRETRY
透明性 動作は暗黙的で見落としやすい エラー処理ルールはパラメータファイルで明示的
私のアドバイス 上記の特定シナリオでのみ使用 本番の単一方向同期における推奨エラー処理ソリューション

REPERROR設定例

主キー競合(ORA-00001)によるINSERTの失敗のみを無視し、「データが見つかりません」(ORA-01403)エラーについては調査のためにプロセスをAbendさせたいとします。

-- rep01.prm
-- REPERROR を使用した精密な制御
REPLICAT rep01
USERIDALIAS ogg_tgt DOMAIN OracleGoldenGate

-- ORA-00001 エラーに遭遇した場合、操作を discard ファイルに記録して続行
REPERROR (1, DISCARD)

-- ORA-01403 エラーに遭遇した場合、デフォルトの動作(Abend)が実行される
-- (1403に対するルールが定義されていないため)

MAP sales.orders, TARGET sales.orders;

この設定はHANDLECOLLISIONSよりもはるかに安全です。INSERTUPDATEに変換しないため、意図しないデータの上書きを避けることができます。同時に、破棄されたすべての操作をdiscardファイルに記録するため、後で何が起こったかを確認できます。

まとめ

HANDLECOLLISIONSは強力なツールですが、力が大きければリスクも大きくなります。最後に、チェックリストをまとめます。

  • 一時的な問題ですか? -> 使う。ただし、対象は問題のあるテーブルのみに限定し、できるだけ早く削除する計画を立ててください。
  • 一回限りのデータ整合を行っていますか? -> 検討の余地あり。完了後に削除してください。
  • 双方向/Active-Active構成を設定していますか? -> 使う。ただし、唯一の解決策としてではなく、完全なCDR戦略の一部として使用すべきです。
  • 通常の単一方向レプリケーション環境ですか? -> 使わない! 特定の既知のエラーを処理するにはREPERRORを優先します。
  • なぜ失敗するかわからず、ただプロセスを動かしたいだけですか? -> 絶対に使わない! それは問題を覆い隠しているだけです。まず根本原因を診断してください。

データ同期の核心は一貫性信頼性です。プロセスの表面的な「継続的な実行」と引き換えにこれらを犠牲にする近道は、最終的にはより大きな代償を払うことになります。