Oracle Change Data Capture (CDC)


Eine CDC-Replikation stellt eine kostengünstig und einfach zu implementierende Lösung im Datawarehouse-Bereich dar um Daten zwischen verteilten Datenbanken zu Replizieren


Überblick

Oracle CDC Replikation kann sowohl syncron als auch asyncron eingesetzt werden und stelle eine einfach zu implementierende Lösung für die Datenreplikation zwischen Oracle Datenbanken dar. CDC unterstützt dabei auch mehrere Consumer.

Die Funktionsweise anhand eines Beispiels

Im folgenden soll anhand eines Beispiels die Replikation einer Tabelle mittels eines syncronen CDC-Sets dargestellt werden.
Für eine mit CDC zu replizierende Tabelle legt Oracle einen Change Table an, in dem alle Änderungen der zu replizierenen Basistabelle mitgeschrieben werden. Jeder Consumer erhält einen Subscribe-View, der die für ihn notwendigen Daten enthält. Jeder Consumer kann voneinander unabhängig seine bereits verarbeiteten (konsumierten) Daten aus dem View entfernen.

Ausgangspunkt ist die Beispieltabelle DEPT, für die im nächsten Schritt eine ChangeTable angelegt wird, Löschen und Erweiterungen der Change Tabelle sind ebefalls als Beispiel angegeben.

select * from DEPT;

DEPTNO 	DNAME 	LOC
10	ACCOUNTING 	NEW YORK
20	RESEARCH 	DALLAS
30	SALES 		CHICAGO
40	OPERATIONS 	BOSTON

Das Erstellen eines Change Tables erfolgt über Oracle-interne 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;

Falls notwendig kann die so angelegte Tabelle wie folgt gelöscht oder geändert werden:

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;       

Im nächsten Schritt erstellen wir eine Subscription und den zughörigen View. Dieser View sollte in einem Schema angelegt werden, auf welches der Subscriptionsuser Zugriff hat, es sollte nicht in dem Schema liegen, in dem sich der Change-Table befindet.

BEGIN
       DBMS_CDC_SUBSCRIBE.CREATE_SUBSCRIPTION(
       change_set_name   => 'SYNC_SET',
       description       => 'Change data for test',
       subscription_name => 'TEST');
END;
/

Die neue Subscription kann wie folgt geprüft werden_

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 	  	  	TEST

Der View für die Subscription wird wie folgt erstellt:

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 erstellt damit den folgenden 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
  /

Betrieb

Das insert in die Basistabelle erstellt jetzt einen Record in der Change-Tabelle, dieser wird aber im Subscribtionsview erst nach Aufruf der Prozedure 'extent_windo' angezeigt:

Insert into DEPLOY.DEPT
   (DEPTNO, DNAME, LOC)
 Values
   (10, 'ACCOUNTING', 'NEW YORK');
COMMIT;

Dies ergibt einen Record in CLS_DEPT Chaneg Tabelle.

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 	EVERYWHER

Die Subscription muss explizit gestartet werden. Nach der Verarbeitung kann das Subscription-Window erweitert werden.

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 	EVERYWHER

Nach erfolgreicher Verarbeitung der Daten kann das abgearbeitet Datenset (Subscription Window) gelöscht werden. Dies Wird über die PURGE_WINDOW Procedure erreicht.

BEGIN
   DBMS_CDC_SUBSCRIBE.PURGE_WINDOW(
       subscription_name => 'TEST');
END;
/

Die Daten werden dabei aber nicht aus der CDC-Change Tabelle entfernt. Erst wenn alle Subscriber die Daten geladen haben kann die Change-Table mit einem separaten Procedure-Aufruf geleert werden. Vorsicht: in diesem Falle führt Oracle ein 'split Partition' Statement aus welches DML Befehle auf der Basistabelle kurzfristig blokieren. Diese Purge sollte also sehr regelmäßig (minimale Ausführungszeit, daher minimale Verzögerung) oder außerhalb der Zeiten stattfinden, in der die Basistabelle per DML verändert wird.

BEGIN
	dbms_cdc_publish.purge;
END;