Oracle Change Data Capture (CDC)
CDC replication is an inexpensive and easily implemented way to replicate data between distributed databases in a data warehouse environment.
A note on currency: Oracle Change Data Capture has not been part of the database since Oracle Database 12c and has been replaced by Oracle GoldenGate. This page remains as a reference for existing systems. For new work we advise on GoldenGate and on log-based alternatives.
Overview
Oracle CDC replication can be used synchronously or asynchronously and is a straightforward solution for replicating data between Oracle databases. CDC also supports multiple consumers.
How it works, by example
The following example shows how a table is replicated using a synchronous CDC change set.
For every table to be replicated with CDC, Oracle creates a change table in which all changes to the base table are recorded. Each consumer receives a subscriber view containing the data it needs, and each consumer can independently remove the data it has already processed from that view.
The starting point is the sample table DEPT, for which a change table is created
in the next step. Dropping and altering the change table are shown as examples as well.
select * from DEPT;
DEPTNO DNAME LOC
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTONChange tables are created through Oracle-internal packages.
declare
begin
dbms_cdc_publish.create_change_table(
owner => 'DEPLOY',
change_table_name => 'CLS_DEPT',
change_set_name => 'SYNC_SET',
source_schema => 'SCHEMA_OWNER',
source_table => 'DEPT',
column_type_list => '
DEPTNO NUMBER(2),
DNAME VARCHAR2(14),
LOC VARCHAR2(13)',
capture_values=>'both',
rs_id=>'Y',
row_id=>'Y',
user_id=>'N',
timestamp=>'Y',
object_id=>'N',
source_colmap=>'N',
target_colmap=>'N',
options_string=>null);
end;If necessary, a change table created this way can be dropped or altered as follows:
exec dbms_cdc_publish.drop_change_table('DEPLOY','CLS_DEPT','Y');
--
--Erweitern eines Change Tables um die Spalte Loc2
--
begin
dbms_cdc_publish.alter_change_table(
owner => 'DEPLOY',
change_table_name => 'CL_DEPT',
operation => 'ADD',
column_list => 'LOC2 VARCHAR2(13)',
rs_id=>'N',
row_id=>'N',
user_id=>'N',
timestamp=>'N',
object_id=>'N',
source_colmap=>'N',
target_colmap=>'N');
end;In the next step we create a subscription and the associated view. This view should be created in a schema the subscribing user has access to, and it should not reside in the schema that holds the change table.
BEGIN
DBMS_CDC_SUBSCRIBE.CREATE_SUBSCRIPTION(
change_set_name => 'SYNC_SET',
description => 'Change data for test',
subscription_name => 'TEST');
END;
/The new subscription can be verified as follows:
select * from DBA_SUBSCRIPTIONS;
HANDLE SET_NAME USERNAME CREATED STATUS EARLIEST_SCN LATEST_SCN DESCRIPTION LAST_PURGED LAST_EXTENDED SUBSCRIPTION_NAME
1 SYNC_SET SCHEMA_OWNER 05.09.2009 09:56:21 N 1 0 Change data for test TESTThe subscriber view is created like this:
BEGIN
DBMS_CDC_SUBSCRIBE.SUBSCRIBE(
subscription_name => 'TEST',
source_schema => 'SCHEMA_OWNER',
source_table => 'DEPT',
column_list => 'deptno, dname, loc',
subscriber_view => 'V_SUBS_DEPT');
END;
/Oracle then creates the following view:
CREATE OR REPLACE VIEW deploy.v_subs_dept
AS
SELECT operation$, cscn$, commit_timestamp$, row_id$, rsid$, timestamp$,
"DEPTNO", "DNAME", "LOC"
FROM "SCHEMA_OWNER"."CLS_DEPT"
WHERE cscn$ >= 1
AND cscn$ <= 0 WITH READ ONLY
/Operation
An insert into the base table now creates a record in the change table, but that record only
becomes visible in the subscriber view after the procedure extend_window has been
called:
Insert into DEPLOY.DEPT
(DEPTNO, DNAME, LOC)
Values
(10, 'ACCOUNTING', 'NEW YORK');
COMMIT;This produces one record in the change table CLS_DEPT.
OPERATION$ CSCN$ COMMIT_TIMESTAMP$ RSID$ ROW_ID$ TIMESTAMP$ DEPTNO DNAME LOC
I 281474976710655 01.01.4000 1 AAAbloAAFAAAHz2AAA 06.09.2009 16:53:34 50 IT EVERYWHERThe subscription has to be activated explicitly. Once processing is finished, the subscription window can be extended.
BEGIN
DBMS_CDC_SUBSCRIBE.ACTIVATE_SUBSCRIPTION(
subscription_name => 'TEST');
END;
/
BEGIN
DBMS_CDC_SUBSCRIBE.EXTEND_WINDOW(
subscription_name => 'TEST');
END;
select * from DEPLOY.v_subs_dept
OPERATION$ CSCN$ COMMIT_TIMESTAMP$ ROW_ID$ RSID$ TIMESTAMP$ DEPTNO DNAME LOC
I 10151264490285 06.09.2009 16:58:54 AAAbloAAFAAAHz2AAA 06.09.2009 16:53:34 50 IT EVERYWHERAfter the data has been processed successfully, the completed data set — the subscription
window — can be purged. This is done with the PURGE_WINDOW procedure.
BEGIN
DBMS_CDC_SUBSCRIBE.PURGE_WINDOW(
subscription_name => 'TEST');
END;
/Caution: this does not remove the data from the CDC change table.
Only once all subscribers have consumed the data can the change table itself be purged with a
separate procedure call. In that case Oracle issues a split partition statement which
briefly blocks DML on the base table. This purge should therefore run very frequently — so that
each run is short and the delay minimal — or outside the times when the base table is modified by
DML.
BEGIN
dbms_cdc_publish.purge;
END;