GoldenGateでレプリカ表に更新日付を入れる [GoldenGate]
1.はじめに
最近の案件で、GoldenGateを使ってレプリケーションする際に、更新日付を入れられないか、という問い合わせがあった。初回INSERT時と、UPDATEされたときに、それぞれ更新日付を記録したいという要件である。実現方式を調べて、OCIで動作確認したので、備忘までメモしておく。
検証はOCIで、BaseDBと、適当なコンピュート上に構成したGoldenGate(マイクロサービス)で行った。BaseDBは1台の上に、ORADBとORADBREPという2つのPDBを構成し、ORADBのEMP表をORADBREPにレプリケーションした。その際、更新日付のない通常のレプリケーション(EMP表)と更新日付のあるレプリケーション(EMPREP表)の2つのレプリカを作成した。
2.検証モデル
ソース側となるORADBのEMP表は以下の通り。初期データとして100万件入れておく。また、レプリカの初期同期用にダンプを作成する。
EMP表 Name Null? Type ----------------------------------------- -------- ---------------------------- EMPNO NOT NULL NUMBER(7) ENAME VARCHAR2(10) JOB VARCHAR2(9) MGR NUMBER(7) HIREDATE DATE SAL NUMBER(7,2) COMM NUMBER(7,2) DEPTNO NUMBER(7)
ターゲット側となるORADBREPのEMP表、EMPREP表は以下の通り。初期データとして100万件入れておく。EMPREP表には、CRE_DTとUPD_DTが追加されている。初期データとしてソースのダンプをインポートする。EMPREPはカラムが追加されているので、インポート時はNULLで入る。
EMP表 Name Null? Type ----------------------------------------- -------- ---------------------------- EMPNO NOT NULL NUMBER(7) ENAME VARCHAR2(10) JOB VARCHAR2(9) MGR NUMBER(7) HIREDATE DATE SAL NUMBER(7,2) COMM NUMBER(7,2) DEPTNO NUMBER(7) EMPREP表 Name Null? Type ----------------------------------------- -------- ---------------------------- EMPNO NOT NULL NUMBER(7) ENAME VARCHAR2(10) JOB VARCHAR2(9) MGR NUMBER(7) HIREDATE DATE SAL NUMBER(7,2) COMM NUMBER(7,2) DEPTNO NUMBER(7) CRE_DT TIMESTAMP(6)★作成日付 UPD_DT TIMESTAMP(6)★更新日付
次にGGの設定である。エクストラクトの設定は以下の通り。トレイルとして出力する対象として、ORADBのSCOTTスキーマのオブジェクトを指定した。
EXTRACT EORADB USERIDALIAS CORADB_ORADBVM1 DOMAIN ORADBVM1 EXTTRAIL AA TABLE ORADB.SCOTT.*;
レプリキャットの設定は以下の通り。非統合レプリキャットを使った。MAP文でEMP表とEMPREP表にレプリケートする設定としている。このうち、EMPは単純なMAP文(単純に全てのカラムをマッピング)しているが、EMPREPの方はCOLMAPでCRE_DTとUPD_DTカラムに更新日付を入れる処理を追加している。ここが今回のポイントである。
REPLICAT RORAREP USERIDALIAS ORADBREP DOMAIN ORADBVM1 SOURCECATALOG ORADB MAP SCOTT.EMP, TARGET SCOTT.EMP; MAP SCOTT.EMP, TARGET SCOTT.EMPREP, COLMAP(USEDEFAULTS, cre_dt=@IF(@STREQ(@GETENV('GGHEADER','OPTYPE'),'INSERT'),@DATENOW(),@COLSTAT(MISSING)), upd_dt=@IF(@VALONEOF(@GETENV('GGHEADER','OPTYPE'), 'UPDATE', 'SQL COMPUPDATE', 'PK UPDATE'), @DATENOW(), @COLSTAT(MISSING)));
少し補足すると、@GETENV('GGHEADER','OPTYPE')はDMLの種類を返す関数である。この返り値がINSERTなのかUPDATEなのかを、@STREQで文字列が一致するか、@VALONEOFでいくつかの選択肢のうち1つが一致すれば真を返す関数を利用し、@IFで切り替える。設定値は、現在時刻である@DATENOWを設定するか、何も設定しない@COLSTAT(MISSING)を設定する。なお、UPDATEとSQL COMPUPDATEの違いは、UPDATEが全てのカラムを含むのに対し、SQL COMPUPDATEは更新対象となるカラムしか含まない場合である(Oracleは通常更新対象となるカラムしかREDOに含まないが、SQL Serverなどでは全てのカラムをログに含めるものもある)。
3.動作確認
ここでは、ソース側のEMP表EMPNO=1000001のレコードをINSERT、UPDATE(2回)、DELETEを実行して、ターゲット側の状態を確認した。まず、INSERT後の状態である。正しくターゲットのEMP、EMPREP表にレコードが伝搬されている。また、EMPREPには、作成日を示すCRE_DTが入っており、UPD_DTはNULLのままである。
19:57:27 SCOTT@oradb> @insemp Connected. 19:57:30 SCOTT@oradb> @ckemp Connected. ★ソース:EMP EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- ----------------- ---------- ---------- ---------- 1000001 kazuhiro dba 1 20240408 19:57:30 1000 1000 1 Connected. ★ターゲット:EMP EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- ----------------- ---------- ---------- ---------- 1000001 kazuhiro dba 1 20240408 19:57:30 1000 1000 1 ★ターゲット:EMPREP EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO CRE_DT UPD_DT ---------- ---------- --------- ---------- ----------------- ---------- ---------- ---------- -------------------- -------------------- 1000001 kazuhiro dba 1 20240408 19:57:30 1000 1000 1 20240408 19:57:32
次にUPDATE後の状態である。正しくターゲットのEMP、EMPREP表にSAL,COMが+1されて伝搬されている。また、EMPREPには、更新日付を示すUPD_DTが入る。
19:57:35 SCOTT@oradb> @updemp Connected. 19:57:39 SCOTT@oradb> @ckemp Connected. ★ソース:EMP EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- ----------------- ---------- ---------- ---------- 1000001 kazuhiro dba 1 20240408 19:57:39 1001 1001 1 Connected. ★ターゲット:EMP EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- ----------------- ---------- ---------- ---------- 1000001 kazuhiro dba 1 20240408 19:57:39 1001 1001 1 ★ターゲット:EMPREP EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO CRE_DT UPD_DT ---------- ---------- --------- ---------- ----------------- ---------- ---------- ---------- -------------------- -------------------- 1000001 kazuhiro dba 1 20240408 19:57:39 1001 1001 1 20240408 19:57:32 20240408 19:57:42
もう一度UPDATEを実行した後の状態である。正しくターゲットのEMP、EMPREP表にSAL,COMが+1されて伝搬されている。EMPREPは、更新日付を示すUPD_DTが更新されている。
19:57:48 SCOTT@oradb> @updemp Connected. 19:57:53 SCOTT@oradb> @ckemp Connected. ★ソース:EMP EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- ----------------- ---------- ---------- ---------- 1000001 kazuhiro dba 1 20240408 19:57:53 1002 1002 1 Connected. ★ターゲット:EMP EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ---------- ---------- --------- ---------- ----------------- ---------- ---------- ---------- 1000001 kazuhiro dba 1 20240408 19:57:53 1002 1002 1 ★ターゲット:EMPREP EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO CRE_DT UPD_DT ---------- ---------- --------- ---------- ----------------- ---------- ---------- ---------- -------------------- -------------------- 1000001 kazuhiro dba 1 20240408 19:57:53 1002 1002 1 20240408 19:57:32 20240408 19:57:58
DELETEを実行した後は、正しくターゲットのEMP、EMPREP表がDELETEされることも確認した。
4.まとめ
本稿では、GoldenGateを使ってレプリカを作成する際に、更新日付を追加する方法について、実機検証した結果を記載した。日付を入れる処理ロジックは若干複雑であるが、このような柔軟な対応ができるのは、GoldenGateの良いところである。Goldengateの構成方法についてはまた別の機会に触れたいと思う。
参考
[1]Reference for Oracle GoldenGate, 2.18 @GETENV
2024-04-09 23:36