今天是2014-08-19,我今天收到csdn给我发的申请博客专家的邀请,自己感觉实在惭愧啊。自从换了工作也一直没有精力在写点东西了。今天我一个同事,在群里贴出了一个数据比对的包(DBMS_COMPARISON),但是这个包相比用的比较少。所以今天就谈谈这个工具包的使用吧。
对于经常完数据迁移的朋友来说,在数据挪动之后,最重要也是最关键和最关心的一个问题是,目标端和源端的数据是否一致。数据的一致是否关系着大型oracle数据库数据迁移的成败与否。目前很多公司都开始研发自己的对比工具,如dsg的基于rowid的比对、基于minus的比对等等。但是数据库本身也是给我们提供了一个数据比对的接口,那就是这个DBMS_COMPARISON软件包。
DBMS_COMPARISION简介:
这个软件包是oracle提供的可以再两个数据之间做object是比对。并且呢如果在比对过程中如果源端数据和目标端数据不一致,那么可以选择是从源端在将数据复制到目标端,还是从目标端在复制到源端,最终达到数据一致性的结果。该包也是通过创建dblink来实现的。这个工具的使用大体分为四步:
第一步:使用create_compare去创建一个比对动作
第二步:使用compare函数去进行数据对象之间的比对
第三步:我们在去查看比对结果,相应的record会记录到不同视图中如下:
DBA_COMPARISON_SCAN
USER_COMPARISON_SCAN
DBA_COMPARISON_SCAN_VALUES
USER_COMPARISON_SCAN_VALUES
DBA_COMPARISON_ROW_DIF
USER_COMPARISON_ROW_DIF
第四不:如果数据不一致,那么可以使用convert去将数据同步
大家可能会说,如果我进行了两次数据比对,那么如何区分呢,这就是oracle自己会给你设计一个标示了。这个函数是recheck。后续介绍:
还有一个问题,那就是这个包能做哪些数据比对?
答案是:对表、视图、物化视图、同义词等
DBMS_COMPARISION限制:
当然了任何一个工具都有自己的限制,那么这个包呢?
1、对于源端数据库版本必须是高于11.1,对于目标端数据库版本必须高于10.1
2.对于所有比对的数据库对象,必须是共享对象,也就是说每个对象的列个数和列的类型必须一致。如果列不一致,那么需要将比对的列使用column_list做个列表。
Database objects of different types can be compared and converged at different databases. For example, a table at one database and a materialized view at another database can be compared and converged with this package.
以上是说了比较容易理解的限制,下面在说一下索引列的限制:
1、在全库比对模式下,必须要有一个在 number, timestamp, interval, or DATE
数据类型的单一索引列,或是仅仅有一个包括这几种数据类型的复合索引,但是这个复合索引中设计到的列必须都是not null或是其中一列是一个主键列。
2、
For the scan modes CMP_SCAN_MODE_FULL
and CMP_SCAN_MODE_CUSTOM
to be supported, the database objects must have one of the following types of indexes:
-
A single-column index on a number, timestamp, interval,
DATE
,VARCHAR2
, orCHAR
data type column -
A composite index that only includes number, timestamp, interval,
DATE
,VARCHAR2
, orCHAR
columns. Each column in the composite index must either have aNOT
NULL
constraint or be part of the primary key.
如果数据库没有满足这些要求,那么这个包将无法进行数据比对。
if the database objects have only one index, and it is a composite index that includes a
NUMBER
column and an NCHAR
column, then the DBMS_COMPARISON
package does not support them.
If these constraints are not present on a table, then use the index_schema_name
and
index_name
parameters in the CREATE_COMPARISON
procedure to specify an index whose columns satisfy this requirement.
When a single index value identifies both a local row and a remote row, the two rows must be copies of the same row in the replicated tables. In addition, each pair of copies of the same row must always have the same index value.
DBms_comparison不支持的数据类型:
LONG、LANG RAW、ROWID、urowid、clob、nclob、blob、bfile另外还有如下两种:
1、udt(user-defined types,including object types, REF
s, varrays, and nested tables)
2、oracle-supplied type (including any types, XML types, spatial types, and media types)
好了,了解这些后,我们就开始去亲自做一下,光说不练那不行。
第一创建dblink:
SQL> select * from dba_sys_privs rhys where rhys.privilege like upper('%link%'); GRANTEE PRIVILEGE ADM ------------------------------ ---------------------------------------- --- SYS DROP PUBLIC DATABASE LINK NO SYS CREATE DATABASE LINK NO OWB$CLIENT CREATE DATABASE LINK NO IMP_FULL_DATABASE CREATE PUBLIC DATABASE LINK NO RECOVERY_CATALOG_OWNER CREATE DATABASE LINK NO DBA DROP PUBLIC DATABASE LINK YES IMP_FULL_DATABASE DROP PUBLIC DATABASE LINK NO OWBSYS CREATE DATABASE LINK YES IMP_FULL_DATABASE CREATE DATABASE LINK NO SYS CREATE PUBLIC DATABASE LINK NO DBA CREATE PUBLIC DATABASE LINK YES GRANTEE PRIVILEGE ADM ------------------------------ ---------------------------------------- --- DBA CREATE DATABASE LINK YES 12 rows selected. SQL> grant create database link to scott; Grant succeeded.
SQL> create database link comparison_link connect to scott identified by root using 'orac1'; Database link created. SQL> show user USER is "SCOTT" SQL> select * from scott.emp@comparison_link; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DEP ---------- ---------- --------- ---------- --------- ---------- ---------- ---------- ------------------------------ 7369 SMITH CLERK 7902 17-DEC-80 800 20 7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30 7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 7566 JONES MANAGER 7839 02-APR-81 2975 20 7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30 7698 BLAKE MANAGER 7839 01-MAY-81 2850 30 7782 CLARK MANAGER 7839 09-JUN-81 2450 10 7788 SCOTT ANALYST 7566 19-APR-87 3000 20 7839 KING PRESIDENT 17-NOV-81 5000 10 7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30 7876 ADAMS CLERK 7788 23-MAY-87 1100 20 EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO DEP ---------- ---------- --------- ---------- --------- ---------- ---------- ---------- ------------------------------ 7902 AMY ANALYST 7566 03-DEC-81 3000 20 12 rows selected. SQL>
第二步创建比对任务:
对了忘记提一下权限了,对于该包,要有如下权限:
SQL> grant execute on dbms_comparison to scott; Grant succeeded. SQL> grant execute_catalog_role to scott; Grant succeeded. SQL>
SQL> begin 2 dbms_comparison.create_comparison( 3 comparison_name=>'test1', 4 schema_name=>'SCOTT', 5 object_name=>'DEPT', 6 dblink_name=>'comparison_link' 7 ); 8 end; 9 / PL/SQL procedure successfully completed. SQL>
好这样就做完第一步了。
当源端和目标端数据对象的列不一致的情况会出现如下错误:
SQL> begin 2 dbms_comparison.create_comparison( 3 comparison_name=>'test1', 4 schema_name=>'SCOTT', 5 object_name=>'EMP', 6 dblink_name=>'comparison_link' 7 ); 8 end; 9 / begin * ERROR at line 1: ORA-23625: Table shapes of SCOTT.EMP and SCOTT.EMP@COMPARISON_LINK did not match. ORA-06512: at "SYS.DBMS_COMPARISON", line 5008 ORA-06512: at "SYS.DBMS_COMPARISON", line 448 ORA-06512: at line 2
那么怎么办呢?和我说的是做一个column_list;
第二步开始进行数据比对:
SQL> declare 2 compare_info dbms_comparison.comparison_type; 3 compare_return boolean; 4 begin 5 compare_return := dbms_comparison.compare (comparison_name=>'test1', 6 scan_info=>compare_info, 7 perform_row_dif=>TRUE); 8 9 if compare_return=TRUE 10 then 11 dbms_output.put_line('the tables are equivalent.'); 12 else 13 dbms_output.put_line('Bad news... there is data divergence.'); 14 dbms_output.put_line('Check the dba_comparison and dba_comparison_scan_summary views for locate the differences for scan_id:'||compare_info.scan_id); 15 end if; 16 end; 17 / the tables are equivalent. PL/SQL procedure successfully completed. SQL>
第三步查看比对结果:
SQL> select * from user_comparison_scan 2 ; COMPARISON_NAME SCAN_ID PARENT_SCAN_ID ROOT_SCAN_ID STATUS CURRENT_DIF_COUNT INITIAL_DIF_COUNT COUNT_ROWS S LAST_UPDATE_TIME -------------------- ---------- -------------- ------------ ---------------- ----------------- ----------------- ---------- - ---------------------------------------- TEST1 1 1 SUC 0 0 4 N 19-AUG-14 11.05.42.780593 PM TEST1 2 2 SUC 0 0 4 N 19-AUG-14 11.11.37.613343 PM SQL> select * from user_comparison_row_dif; no rows selected SQL>
好了,简简单单就到这了。
当然如果敢兴趣可以自己在测试其他的。
我要把数据清掉了:
SQL> begin 2 dbms_comparison.purge_comparison( 3 comparison_name=>'test1'); 4 end; 5 / PL/SQL procedure successfully completed. SQL> select * from user_comparison_scan; no rows selected SQL>
that‘s all!