2つのDBでマルチマスタレプリケーションしてみました。
2つDBを作成して、この間で互いにレプリケーションしてみます。
Net Services の設定をして、それぞれこの名前でつながるようにしておきます。
入っていなければ、$ORACLE_HOME/rdbms/admin/utlsampl.sql からインストールしておきます。
#pre{{
MVIEW も使わず、最も簡単な構成で進めました。
基本的にはマニュアルに従うだけです。
sdb1.sql を下記のように書いて、sqlplus から流します。
#pre{{
#pre{{
connect system/oracle@sdb1.sugimura.cc
CREATE USER repadmin IDENTIFIED BY repadmin; BEGIN
DBMS_REPCAT_ADMIN.GRANT_ADMIN_ANY_SCHEMA ( username => 'repadmin');
END; /
GRANT COMMENT ANY TABLE TO repadmin; GRANT LOCK ANY TABLE TO repadmin; GRANT SELECT ANY DICTIONARY TO repadmin;
BEGIN
DBMS_DEFER_SYS.REGISTER_PROPAGATOR ( username => 'repadmin');
END; /
BEGIN
DBMS_REPCAT_ADMIN.REGISTER_USER_REPGROUP ( username => 'repadmin', privilege_type => 'receiver', list_of_gnames => NULL);
END; /
CONNECT repadmin/repadmin@sdb1.sugimura.cc
BEGIN
DBMS_DEFER_SYS.SCHEDULE_PURGE ( next_date => SYSDATE, interval => 'SYSDATE + 1/24', delay_seconds => 0);
END; /
spool off quit }}
SDB1 とほぼ同じです。
#pre{{
conn system/oracle@sdb2.sugimura.cc
CREATE USER repadmin IDENTIFIED BY repadmin;
BEGIN
DBMS_REPCAT_ADMIN.GRANT_ADMIN_ANY_SCHEMA ( username => 'repadmin');
END; /
GRANT COMMENT ANY TABLE TO repadmin; GRANT LOCK ANY TABLE TO repadmin; GRANT SELECT ANY DICTIONARY TO repadmin;
BEGIN
DBMS_DEFER_SYS.REGISTER_PROPAGATOR ( username => 'repadmin');
END; /
BEGIN
DBMS_REPCAT_ADMIN.REGISTER_USER_REPGROUP ( username => 'repadmin', privilege_type => 'receiver', list_of_gnames => NULL);
END; /
CONNECT repadmin/repadmin@sdb2.sugimura.cc
BEGIN
DBMS_DEFER_SYS.SCHEDULE_PURGE ( next_date => SYSDATE, interval => 'SYSDATE + 1/24', delay_seconds => 0);
END; /
spool off quit }}
#pre{{
conn repadmin/repadmin@sdb1.sugimura.cc create database link sdb2.sugimura.cc connect to repadmin identified by repadmin;
conn repadmin/repadmin@sdb2.sugimura.cc create database link sdb1.sugimura.cc connect to repadmin identified by repadmin;
BEGIN
DBMS_DEFER_SYS.SCHEDULE_PUSH ( destination => 'sdb2.sugimura.cc', interval => 'SYSDATE + (1/144)', next_date => SYSDATE, parallelism => 1, execution_seconds => 1500, delay_seconds => 1200);
END; /
BEGIN
DBMS_DEFER_SYS.SCHEDULE_PUSH ( destination => 'sdb1.sugimura.cc', interval => 'SYSDATE + (1/144)', next_date => SYSDATE, parallelism => 1, execution_seconds => 1500, delay_seconds => 1200);
END; /
spool off quit }}
マスター・グループを作成したサイトが 「マスター定義サイト」となります。 SDB1 をマスター定義サイトとします。
scott_repg という名前にしました。
#pre{{ conn repadmin/repadmin@SDB1.sugimura.cc
DBMS_REPCAT.CREATE_MASTER_REPGROUP ( gname => 'scott_repg');END; / }}
scott_repg に4つの表を追加します。
#pre{{ conn repadmin/repadmin@SDB1.sugimura.cc
DBMS_REPCAT.CREATE_MASTER_REPOBJECT ( gname => 'scott_repg', type => 'TABLE', oname => 'dept', sname => 'scott', use_existing_object => TRUE, copy_rows => FALSE);END; /
BEGIN
DBMS_REPCAT.CREATE_MASTER_REPOBJECT ( gname => 'scott_repg', type => 'TABLE', oname => 'emp', sname => 'scott', use_existing_object => TRUE, copy_rows => FALSE);
END; /
BEGIN
DBMS_REPCAT.CREATE_MASTER_REPOBJECT ( gname => 'scott_repg', type => 'TABLE', oname => 'bonus', sname => 'scott', use_existing_object => TRUE, copy_rows => FALSE);
END; /
BEGIN
DBMS_REPCAT.CREATE_MASTER_REPOBJECT ( gname => 'scott_repg', type => 'TABLE', oname => 'salgrade', sname => 'scott', use_existing_object => TRUE, copy_rows => FALSE);
END; / }}
レプリケーション先である SDB2 を追加します。
#pre{{ conn repadmin/repadmin@SDB1.sugimura.cc
DBMS_REPCAT.ADD_MASTER_DATABASE ( gname => 'scott_repg', master => 'sdb2.sugimura.cc', use_existing_objects => TRUE, copy_rows => FALSE, propagation_mode => 'ASYNCHRONOUS');END; / }}
dba_repsites で設定を確認します。SDB2 があればOKです。
#pre{{
GNAME DBLINK MAS
SCOTT_REPG SDB1.SUGIMURA.CC Y SCOTT_REPG SDB2.SUGIMURA.CC N
SQL> }}
必要なパッケージやトリガーを作るようです。
#pre{{ conn repadmin/repadmin@SDB1.sugimura.cc
BEGIN
DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT ( sname => 'scott', oname => 'dept', type => 'TABLE', min_communication => TRUE);
END; /
BEGIN
DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT ( sname => 'scott', oname => 'emp', type => 'TABLE', min_communication => TRUE);
END;
/ BEGIN
DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT ( sname => 'scott', oname => 'bonus', type => 'TABLE', min_communication => TRUE);
END; /
BEGIN
DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT ( sname => 'scott', oname => 'salgrade', type => 'TABLE', min_communication => TRUE);
END; / }}
dba_repcatlog が空になると始められるとのことですが、 このような状態になってしまいました。
#pre{{ SQL> select count(*) from dba_repcatlog where gname = 'SCOTT_REPG';
COUNT(*)
19
SQL> }}
詳しく見てみます。
#pre{{ SQL> col status format a20 SQL> col sname format a10 SQL> col oname format a10 SQL> select status, sname, oname from dba_repcatlog where gname = 'SCOTT_REPG';
STATUS SNAME ONAME
AWAIT_CALLBACK SCOTT DEPT READY SCOTT DEPT AWAIT_CALLBACK AWAIT_CALLBACK SCOTT DEPT AWAIT_CALLBACK SCOTT BONUS AWAIT_CALLBACK SCOTT SALGRADE AWAIT_CALLBACK SCOTT EMP AWAIT_CALLBACK SCOTT_REPG -1 READY SCOTT_REPG -1 READY SCOTT DEPT READY SCOTT EMP
STATUS SNAME ONAME
AWAIT_CALLBACK SCOTT EMP READY SCOTT EMP READY SCOTT BONUS AWAIT_CALLBACK SCOTT BONUS READY SCOTT BONUS READY SCOTT SALGRADE AWAIT_CALLBACK SCOTT SALGRADE READY SCOTT SALGRADE
19行が選択されました。
SQL> }}
初期化パラメータ job_queue_processes が 0 になっていたのが原因でした。 2サイトあるので、2にして上げ直します。
#pre{{ SQL> select count(*) from dba_repcatlog where gname = 'SCOTT_REPG';
COUNT(*)
11
SQL> }}
減りましたが0にはなりません。
STATUS が ERROR となっている行がありました。
#pre{{ SQL> select status, message from dba_repcatlog where gname = 'SCOTT_REPG';
STATUS
MESSAGE
ERROR ORA-23416: 表"SCOTT"."BONUS"に主キー制約がありません。
ERROR ORA-23416: 表"SCOTT"."BONUS"に主キー制約がありません。
ERROR ORA-23416: 表"SCOTT"."SALGRADE"に主キー制約がありません。
STATUS
MESSAGE
ERROR ORA-23416: 表"SCOTT"."SALGRADE"に主キー制約がありません。
SQL> }}
そうですか、というわけで制約を追加します。
#pre{{ SQL> conn scott/tiger@SDB1 接続されました。 SQL> alter table bonus add constraint bonus_pk primary key (ename, job);
表が変更されました。
SQL> alter table salgrade add constraint salgrade_pk primary key (grade);
表が変更されました。
SQL> }}
SDB2 でも追加しておいたほうがいいのかなということで、 こちらでも。
#pre{{ SQL> conn scott/tiger@SDB2 接続されました。 SQL> alter table bonus add constraint bonus_pk primary key (ename, job);
表が変更されました。
SQL> alter table salgrade add constraint salgrade_pk primary key (grade);
表が変更されました。
SQL> }}
作り直すため、オブジェクトを消します。
#pre{{ conn repadmin/repadmin@SDB1.sugimura.cc
DBMS_REPCAT.DROP_MASTER_REPOBJECT ( type => 'TABLE', oname => 'bonus', sname => 'scott');END; /
BEGIN
DBMS_REPCAT.DROP_MASTER_REPOBJECT ( type => 'TABLE', oname => 'salgrade', sname => 'scott');
END; / }}
オブジェクトを消したらログも消します。
#pre{{ SQL> exec dbms_repcat.purge_master_log( id=>NULL, source=>NULL, gname=>'SCOTT_REPG');
PL/SQLプロシージャが正常に完了しました。
SQL> SQL> select count(*) from dba_repcatlog where gname = 'SCOTT_REPG';
COUNT(*)
0
SQL> }}
まっさらにしたので、また作り直します。
#pre{{
DBMS_REPCAT.CREATE_MASTER_REPOBJECT ( gname => 'scott_repg', type => 'TABLE', oname => 'bonus', sname => 'scott', use_existing_object => TRUE, copy_rows => FALSE);END; /
BEGIN
DBMS_REPCAT.CREATE_MASTER_REPOBJECT ( gname => 'scott_repg', type => 'TABLE', oname => 'salgrade', sname => 'scott', use_existing_object => TRUE, copy_rows => FALSE);
END; /
DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT ( sname => 'scott', oname => 'bonus', type => 'TABLE', min_communication => TRUE);END; /
BEGIN
DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT ( sname => 'scott', oname => 'salgrade', type => 'TABLE', min_communication => TRUE);
END; / }}
再度 dba_repcatlog を確認してみます。
#pre{{ SQL> select count(*) from dba_repcatlog where gname = 'SCOTT_REPG';
COUNT(*)
0
SQL> }}
ようやくこれで準備完了です。
#pre{{ conn repadmin/repadmin@SDB1.sugimura.cc
BEGIN
DBMS_REPCAT.RESUME_MASTER_ACTIVITY ( gname => 'scott_repg');
END; / }}
DEPT表に1行追加してみます。
#pre{{ SQL> conn scott/tiger@sdb1 接続されました。 SQL> insert into dept values (50, 'WORK1', 'TOKYO');
1行が作成されました。
SQL> commit;
コミットが完了しました。
SQL> }}
しばらくしてから SDB2 で見てみます。
#pre{{ SQL> conn scott/tiger@sdb2 接続されました。 SQL> set lines 1000 SQL> select * from dept;
DEPTNO DNAME LOC
10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON 50 WORK1 TOKYO
SQL> }}
SDB1 で追加した行が SDB2 に反映されました。
今度は SALGRADE 表から1行消してみます。
#pre{{ SQL> conn scott/tiger@sdb2 接続されました。 SQL> select * from salgrade;
GRADE LOSAL HISAL
1 700 1200 2 1201 1400 3 1401 2000 4 2001 3000 5 3001 9999
SQL> delete from salgrade where grade = 3;
1行が削除されました。
SQL> commit;
コミットが完了しました。
SQL> select * from salgrade;
GRADE LOSAL HISAL
1 700 1200 2 1201 1400 4 2001 3000 5 3001 9999
SQL> }}
SDB1 で確認してみます。
#pre{{ SQL> conn scott/tiger@sdb1 接続されました。 SQL> select * from salgrade;
GRADE LOSAL HISAL
1 700 1200 2 1201 1400 4 2001 3000 5 3001 9999
SQL> }}
ちゃんと反映されています。
マスター・サイトの追加や削除など、 管理については別ページにしました。