Tuesday, January 28, 2014

GoldenGate: 12c Conflict Detection and Resolution (CDR)

One of my favorite 12c enhancement for GoldenGate is its new conflict detection resolution (CDR) feature for two way replication.  In previous version, the replicat parameter files had to contain SQLEXEC commands that would query the target table before applying any DML.  This added an additional call to the database and slowed performance.

CDR provides new parameters that simplify the detection and resolution of conflicting data.  Here are some of the optional keywords that can be combined with the new RESOLVECONFLICT parameter.

UPDATEROWEXISTS
UPDATEROWMISSING
INSERTROWEXISTS
INSERTROWMISSING
DELETEROWEXISTS
DELETEROWMISSING

These can be configured to regard one data source the master and always overwrite the other.  They can utilize a timestamp column that determines the "winner" based on the most recent data.  For data such as inventory, the "delta" can be used to make changes to both sites and adjust the value rather than simply replicating it.

GoldenGate requires the "before" images to be captured for all relevant columns in the source database.  Here is how trandata can be configured for all columns in the SCOTT schema in the PDBORCL pluggable database.

GGSCI (oel1.localdomain) 103> ADD SCHEMATRANDATA pdborcl.scott ALLCOLS

2014-01-20 15:21:04  INFO    OGG-01788  SCHEMATRANDATA has been added on schema scott.

2014-01-20 15:21:05  INFO    OGG-01976  SCHEMATRANDATA for scheduling columns has been added on schema scott.

2014-01-20 15:21:05  INFO    OGG-01977  SCHEMATRANDATA for all columns has been added on schema scott.


In addition, the extract parameter files need the GETBEFORECOLS option as a part of the TABLE parameter.  In the example below, the extract will capture all of the columns in the SCOTT.ITEMS table for each update and delete.  The before image of each of these records will be loaded into the trail file.

EXTRACT e1aa
USERIDALIAS ggsadm domain d1
LOGALLSUPCOLS
EXTTRAIL ./dirdat/aa

TABLE pdborcl.scott.emp;
TABLE pdborcl.scott.dept;

SOURCECATALOG pdborcl
TABLE scott.bonus;
TABLE scott.salgrade;
TABLE scott.items,
  GETBEFORECOLS
    (
    ON UPDATE ALL,
    ON DELETE ALL
    );


The final step is to configure the replicat parameter files with the RESOLVECONFLICT paramter.  In the example below, CDR is configured for the SCOTT.ITEMS table.  If the record exists on the target for an update, the DML_TIMESTAMP column will be compared, and the record with the most recent time will "win" for all of the columns except QTY_ON_HAND.  This column will be updated with the difference between the old and new record value on the source using the UPDATEROWEXISTS and USEDELTA keywords.

For example:  If QTY_ON_HAND is updated on both databases in a bi-directional replication setup, the change needs to be reflected appropriately on each system.  Let's say that the value on both system starts out at 22.  The value on DB1 is decremented to 18, while the value on DB2 is incremented to 30.  When the two updates pass each other and get applied on their respective targets, the records cannot simply be replicated as is.  Simple arithmetic must be applied to both sides in order to account for the change in inventory on both sides.  The "delta" for DB1 is -4.  The "delta" for DB2 is +8.  Therefore, the value on DB1 (18) will be incremented by 8 for a new total of 26. The value on DB2 (30) will be decremented by 4 for a new total of 26.  Now, rather than having a "winner", both sources of data will be equal based on the "delta".

The replicat parameter file below is set up for such a situation.

REPLICAT r2aa
USERIDALIAS ggsadm domain d2
ASSUMETARGETDEFS

MAP pdborcl.scott.emp, TARGET scott.emp;
MAP pdborcl.scott.dept, TARGET scott.dept;

SOURCECATALOG pdborcl
MAP scott.bonus, TARGET scott.bonus;
MAP scott.salgrade, TARGET scott.salgrade;
MAP scott.items, TARGET scott.items,
  COMPARECOLS
    (
    ON UPDATE KEYINCLUDING (item_name, qty_on_hand, sales_price, dml_timestamp),
    ON DELETE KEYINCLUDING (item_name, qty_on_hand, sales_price, dml_timestamp)
    ),
  RESOLVECONFLICT (UPDATEROWEXISTS,
                     (delta_combine, USEDELTA, COLS (qty_on_hand)),
                     (DEFAULT, USEMAX (dml_timestamp))),
  RESOLVECONFLICT (INSERTROWEXISTS, (DEFAULT, USEMAX (dml_timestamp))),
  RESOLVECONFLICT (DELETEROWEXISTS, (DEFAULT, OVERWRITE)),
  RESOLVECONFLICT (UPDATEROWMISSING, (DEFAULT, OVERWRITE)),
  RESOLVECONFLICT (DELETEROWMISSING, (DEFAULT, DISCARD))
  ;

1 comment: