高階複製-7、測試是否非主鍵表的同步

lirenquan發表於2011-01-13

由於高階複製中明確要求複製的表需要有主鍵,那麼如果沒有主鍵複製是否能正常進行,如果不能正常進行那麼有什麼補救措施,這就是本節要測試的內容。
1、在主體定義表中建立不含主鍵的表,試圖將它加入主體組(複製組),看是否能完成複製:
1、1主體定義站點:
SQL> create table tb_test_nokey_rep(id int,name varchar2(10));

Table created.

SQL> declare
  2  i int;
  3  begin
  4  for i in 1..100 loop
  5     insert into tb_test_nokey_rep values(i,'liyx');
  6  end loop;
  7  commit;
  8  end;
  9  /

PL/SQL procedure successfully completed.

SQL> select count(1) from tb_test_nokey_rep;

  COUNT(1)
----------
       100
2、非主體定義站點
SQL> select table_name from user_tables;

TABLE_NAME
------------------------------
TB_TEST_CREATE_REP
TB_TEST_CREATE_REP2
TB_TEST_REP

SQL> create table tb_test_nokey_rep as select * from reptest.tb_test_nokey_rep@master.com;

Table created.

SQL> select count(1) from tb_test_nokey_rep;

  COUNT(1)
----------
       100

2、將測試表加入到複製組
SQL> execute dbms_repcat.create_master_repobject(sname=>'reptest',oname=>'tb_test_nokey_rep', type=>'table',use_existing_object=>true,gname=>'rep_mytest',copy_rows=>false);

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.resume_master_activity('REP_MYTEST',true);

PL/SQL procedure successfully completed.

3、測試在複製物件中修改資料,檢視同步情況:
3.1、主體定義站點:

SQL> select * from reptest.tb_test_nokey_rep where id=100;

        ID NAME
---------- --------------------
       100 liyx

SQL> insert into reptest.tb_test_nokey_rep values(100,'lirq');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from reptest.tb_test_nokey_rep where id=100;

        ID NAME
---------- --------------------
       100 liyx
       100 lirq
3.2 非主體定義站點:
插入前:
SQL> select * from tb_test_nokey_rep where id=100;

        ID NAME
---------- --------------------
       100 liyx

SQL> reptest.tb_test_nokey_rep where id=100;
SP2-0734: unknown command beginning "reptest.tb..." - rest of line ignored.
插入後:
SQL> select * from reptest.tb_test_nokey_rep where id=100;

        ID NAME
---------- --------------------
       100 liyx

看來,沒有主建的主體複製物件,是無法同步的。

4、補救措施:
4.1、依據:
Q:如果一張表沒有主鍵,又確實需要複製,怎麼辦?
A:不建議在高階複製的環境中出現這樣的情況,應該確保每張表都有主鍵。如果確實存在這種情況,那麼需要用DBMS_REPCAT.SET_COLUMNS 來生成代用主鍵。
execute DBMS_REPCAT.SET_COLUMNS(sname => test', name => 'tabel', column_list =>'col1,col2,col3,col4');
其中column_list 是用逗號隔開的欄位列表,不能有空格。
注意:不要在執行set_columns 之前生成對於沒有主鍵的物件的複製支援,也就是不要執行generate_replication_support,否則會導致all_repobject 檢視中該物件狀態變為ERROR,而無法再次set_columns。
如果誤執行了複製支援而又沒有成功,那麼需要刪除掉這個複製物件再重新生成。也就是在對沒有主鍵的表生成複製的時候,必須遵循以下順序:
create_master_repobject -> set_columns -> generate_replication_support

4.2、刪除複製物件組:
SQL> execute dbms_repcat.drop_master_repobject(sname=>'reptest',oname=>'tb_test_nokey_rep',type=>'table');

PL/SQL procedure successfully completed.

4.3、再次建立物件組
SQL>  execute dbms_repcat.create_master_repobject(sname=>'reptest',oname=>'tb_test_nokey_rep', type=>'table',use_existing_object=>true,gname=>'rep_mytest',copy_rows=>true);

PL/SQL procedure successfully completed.

SQL> exec dbms_repcat.SET_COLUMNS(sname=>'reptest',oname=>'tb_test_nokey_rep',column_list=>'id,name');

PL/SQL procedure successfully completed.

SQL> exec dbms_repcat.resume_master_activity('rep_mytest',true);

PL/SQL procedure successfully completed.

SQL> select * from reptest.tb_test_nokey_rep where id=100;

        ID NAME
---------- --------------------
       100 liyx
       100 lirq
在非主體定義站點測試:
SQL> select * from reptest.tb_test_nokey_rep where id=100;

        ID NAME
---------- --------------------
       100 liyx

還是沒有同步.

檢視dba_repobject發現複製物件並沒有產生複製支援,暈:
SQL> col sname for a10;
SQL> col oname for a10;
SQL> col gname for a10;
SQL> select gname,sname,oname,status from dba_repobject;

GNAME      SNAME      ONAME      STATUS
---------- ---------- ---------- --------------------
REP_MYTEST REPTEST    TB_TEST_CR VALID
                      EATE_REP

REP_MYTEST REPTEST    TB_TEST_CR ERROR
                      EATE_REP2

REP_MYTEST REPTEST    TB_TEST_NO VALID
                      KEY_REP

REP_MYTEST REPTEST    TB_TEST_RE VALID
                      P

GNAME      SNAME      ONAME      STATUS
---------- ---------- ---------- --------------------

REP_MYTEST REPTEST    TB_TEST_RE VALID
                      P$RP

REP_MYTEST REPTEST    TB_TEST_RE VALID
                      P$RP


6 rows selected.

再次回頭使複製物件產生複製支援:
SQL> execute dbms_repcat.suspend_master_activity('rep_mytest');

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.GENERATE_REPLICATION_SUPPORT(sname=>'reptest',oname=>'tb_test_nokey_rep',type=>'table');

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.GENERATE_REPLICATION_SUPPORT(sname=>'reptest',oname=>'tb_test_create_rep',type=>'table');

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.resume_master_activity('rep_mytest',true);

PL/SQL procedure successfully completed.

SQL> select gname,sname,oname,status from dba_repobject;

GNAME      SNAME      ONAME      STATUS
---------- ---------- ---------- --------------------
REP_MYTEST REPTEST    TB_TEST_CR VALID
                      EATE_REP

REP_MYTEST REPTEST    TB_TEST_CR VALID
                      EATE_REP$R
                      P

REP_MYTEST REPTEST    TB_TEST_CR VALID
                      EATE_REP$R
                      P


GNAME      SNAME      ONAME      STATUS
---------- ---------- ---------- --------------------
REP_MYTEST REPTEST    TB_TEST_CR ERROR
                      EATE_REP2

REP_MYTEST REPTEST    TB_TEST_NO VALID
                      KEY_REP

REP_MYTEST REPTEST    TB_TEST_NO VALID
                      KEY_REP$RP

REP_MYTEST REPTEST    TB_TEST_NO VALID
                      KEY_REP$RP

GNAME      SNAME      ONAME      STATUS
---------- ---------- ---------- --------------------

REP_MYTEST REPTEST    TB_TEST_RE VALID
                      P

REP_MYTEST REPTEST    TB_TEST_RE VALID
                      P$RP

REP_MYTEST REPTEST    TB_TEST_RE VALID
                      P$RP


10 rows selected.

但是在向tb_test_nokey_rep表插入資料時,還是報錯:
SQL> delete from reptest.tb_test_nokey_rep where id=100;
delete from reptest.tb_test_nokey_rep where id=100
*
ERROR at line 1:
ORA-04067: ????stored procedure "REPTEST.TB_TEST_NOKEY_REP$RP" ???
ORA-01085: ?? rpc ? "REPTEST.TB_TEST_NOKEY_REP$RP.REP_DELETE" ?????
ORA-02063: preceding 2 lines from SNAP

這個錯誤就是報儲存過程不存在的問題,算了,還是重新註冊一次。
SQL> execute dbms_repcat.suspend_master_activity('rep_mytest');     

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.drop_master_repobject(sname=>'reptest',oname=>'tb_test_nokey_rep',type=>'table');

PL/SQL procedure successfully completed.

SQL> select sname,oname,status from dba_repobject;

SNAME      ONAME      STATUS
---------- ---------- --------------------
REPTEST    TB_TEST_CR VALID
           EATE_REP

REPTEST    TB_TEST_CR VALID
           EATE_REP$R
           P

REPTEST    TB_TEST_CR VALID
           EATE_REP$R
           P


SNAME      ONAME      STATUS
---------- ---------- --------------------
REPTEST    TB_TEST_CR ERROR
           EATE_REP2

REPTEST    TB_TEST_RE VALID
           P

REPTEST    TB_TEST_RE VALID
           P$RP

REPTEST    TB_TEST_RE VALID
           P$RP

SNAME      ONAME      STATUS
---------- ---------- --------------------


7 rows selected.

SQL> execute dbms_repcat.drop_master_repobject(sname=>'reptest',oname=>'tb_test_create_rep',type=>'table');

PL/SQL procedure successfully completed.


SQL> execute dbms_repcat.drop_master_repobject(sname=>'reptest',oname=>'tb_test_create_rep',type=>'table');

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.create_master_repobject(sname=>'reptest',oname=>'tb_test_nokey_rep', type=>'table',use_existing_object=>true,gname=>'rep_mytest',copy_rows=>true);

PL/SQL procedure successfully completed.

SQL> exec dbms_repcat.SET_COLUMNS(sname=>'reptest',oname=>'tb_test_nokey_rep',column_list=>'id,name');

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.GENERATE_REPLICATION_SUPPORT(sname=>'reptest',oname=>'tb_test_nokey_rep',type=>'table');

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.create_master_repobject(sname=>'reptest',oname=>'tb_test_create_rep', type=>'table',use_existing_object=>true,gname=>'rep_mytest',copy_rows=>true);

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.GENERATE_REPLICATION_SUPPORT(sname=>'reptest',oname=>'tb_test_create_rep',type=>'table');

PL/SQL procedure successfully completed.
SQL> execute dbms_repcat.drop_master_repobject(sname=>'reptest',oname=>'tb_test_create_rep2',type=>'table');

PL/SQL procedure successfully completed.

SQL> select sname,oname,status from dba_repobject;

SNAME      ONAME      STATUS
---------- ---------- --------------------
REPTEST    TB_TEST_CR VALID
           EATE_REP

REPTEST    TB_TEST_CR VALID
           EATE_REP$R
           P

REPTEST    TB_TEST_CR VALID
           EATE_REP$R
           P


SNAME      ONAME      STATUS
---------- ---------- --------------------
REPTEST    TB_TEST_NO VALID
           KEY_REP

REPTEST    TB_TEST_NO VALID
           KEY_REP$RP

REPTEST    TB_TEST_NO VALID
           KEY_REP$RP

REPTEST    TB_TEST_RE VALID
           P

SNAME      ONAME      STATUS
---------- ---------- --------------------

REPTEST    TB_TEST_RE VALID
           P$RP

REPTEST    TB_TEST_RE VALID
           P$RP


9 rows selected.

檢視資料同步的情況:
主體定義節點:
SQL> select count(1) from reptest.tb_test_create_rep;

  COUNT(1)
----------
         3

SQL> select * from reptest.tb_test_create_rep;   

        ID NAME
---------- --------------------
         4 lirq
         1 ???
         2 ???
SQL> select count(1) from reptest.tb_test_nokey_rep;

  COUNT(1)
----------
       101

SQL> select * from reptest.tb_test_nokey_rep where id=100;

        ID NAME
---------- --------------------
       100 liyx
       100 lirq
非主體定義節點:
SQL>  select count(1) from reptest.tb_test_create_rep;

  COUNT(1)
----------
         3

SQL> select * from reptest.tb_test_create_rep;

        ID NAME
---------- ----------
         4 lirq
         1 ???
         2 ???

SQL> select count(1) from reptest.tb_test_nokey_rep;

  COUNT(1)
----------
       100

SQL> select count(1) from reptest.tb_test_nokey_rep;

  COUNT(1)
----------
       100

SQL> select * from reptest.tb_test_nokey_rep where id=100;                     

        ID NAME
---------- --------------------
       100 liyx

對於不含有主鍵的表複製,還是沒有做成功。


檢視錯誤
select source,status,timestamp,master,sname,oname,message from dba_repcatlog
order by timestamp desc
;
 
發現最近的幾次錯誤都是23308或23309
在網上找了下關於23308和23309的錯誤,摘錄如下:
在維護主備庫的高階複製時,發現有一張表始終無法複製,複製時,總是報以下錯誤:

ORA-23309: object TEST.RECORD_DETAIL of type TABLE exists
ORA-23308: object TEST.RECORD_DETAIL does not exist or is invalid
ORA-23419: regenerate replication support before resuming master activity
解決:
偶然的機會,在比較主備庫的表結構時,發現主庫此表的user_id欄位有非空約束,而備庫沒有此約束。
在給備庫此表的user_id欄位加上非空約束後,重新執行高階複製成功。

從內容上來看,說明兩邊表結構不一致時可能會出現這上錯誤。
回到開頭,記得在非主體站點建表是通過CTAS建立的,這確實可能會造成表結構不一致,果然發現兩表的NAME的欄位型別上一個為varchar2(10),另一個為varchar2(20)。下面的調整就很簡單了:


接下來要做的事情就簡單了,請看下流程:
主體定義站點:
SQL> exec dbms_repcat.suspend_master_activity('rep_mytest');

PL/SQL procedure successfully completed.
非主體定義站點:

SQL> drop table reptest.tb_test_nokey_rep;

Table dropped.

SQL> create table reptest.tb_test_nokey_rep(id number(38),name varchar2(20));

Table created.
主體定義站點:
SQL> execute dbms_repcat.create_master_repobject(sname=>'reptest',oname=>'tb_test_nokey_rep', type=>'table',use_existing_object=>true,gname=>'rep_mytest',copy_rows=>true);

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.set_columns(sname=>'reptest',oname=>'tb_test_nokey_rep',column_list=>'id,name');

PL/SQL procedure successfully completed.

SQL> execute dbms_repcat.GENERATE_REPLICATION_SUPPORT(sname=>'reptest',oname=>'tb_test_nokey_rep',type=>'table');

PL/SQL procedure successfully completed.

SQL>
SQL> execute dbms_repcat.resume_master_activity('rep_mytest',true);

PL/SQL procedure successfully completed.

SQL>
SQL> select count(1) from reptest.tb_test_nokey_rep;

  COUNT(1)
----------
       101

SQL> select * from reptest.tb_test_nokey_rep where id=100;

        ID NAME
---------- ----------------------------------------
       100 liyx
       100 lirq
非主體定義站點:
SQL> select count(1) from reptest.tb_test_nokey_rep;

  COUNT(1)
----------
       101

SQL> select * from reptest.tb_test_nokey_rep where id=100;

        ID NAME
---------- --------------------
       100 liyx
       100 lirq


總算是對不含主鍵的複製物件成功進行了複製。

5、順便測試truncate操作是否可以同步:
5.1、操作前:
5.1.1、主體定義站點:
SQL> select count(1) from reptest.tb_test_create_rep;    

  COUNT(1)
----------
         3
5.1.2、非主體定義站點:
SQL> select count(1) from reptest.tb_test_create_rep;

  COUNT(1)
----------
         0
5.2 、操作
SQL> truncate table  reptest.tb_test_create_rep;

Table truncated.
5.3、操作後:
5.3.1、主體定義站點:

SQL> select count(1) from reptest.tb_test_create_rep;

  COUNT(1)
----------
         0
5.3.2、非主體定義站點:
SQL> select count(1) from reptest.tb_test_create_rep;    

  COUNT(1)
----------
         3

從測試結果來看,同步的是DML操作,並不能對DDL操作進行同步,要想將TRUNCATE這種操作進行同步,必須通過重新註冊複製物件來完成

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12350275/viewspace-683780/,如需轉載,請註明出處,否則將追究法律責任。

相關文章