I recently noticed that there is an Oracle-supplied package called DBMS_COMPARISON. It’s been around since Oracle 11g.
As the name implies, we can compare and identify differences in the data between remote and local database objects. If there is a data consistency problem between two environments, the package also gives the possibility to correct the data.
DBMS_COMPARISON in Oracle 19c can compare:
- Tables
- Single-table views
- Materialized views
- Synonyms for tables, single-table views, and materialized views
You can compare objects which are of different types.
Let’s have a look at DBMS_COMPARISON.CREATE_COMPARISON
DBMS_COMPARISON.CREATE_COMPARISON(
comparison_name IN VARCHAR2,
schema_name IN VARCHAR2,
object_name IN VARCHAR2,
dblink_name IN VARCHAR2,
index_schema_name IN VARCHAR2 DEFAULT NULL,
index_name IN VARCHAR2 DEFAULT NULL,
remote_schema_name IN VARCHAR2 DEFAULT NULL,
remote_object_name IN VARCHAR2 DEFAULT NULL,
comparison_mode IN VARCHAR2 DEFAULT CMP_COMPARE_MODE_OBJECT,
column_list IN VARCHAR2 DEFAULT '*',
scan_mode IN VARCHAR2 DEFAULT CMP_SCAN_MODE_FULL,
scan_percent IN NUMBER DEFAULT NULL,
null_value IN VARCHAR2 DEFAULT CMP_NULL_VALUE_DEF,
local_converge_tag IN RAW DEFAULT NULL,
remote_converge_tag IN RAW DEFAULT NULL,
max_num_buckets IN NUMBER DEFAULT CMP_MAX_NUM_BUCKETS,
min_rows_in_bucket IN NUMBER DEFAULT CMP_MIN_ROWS_IN_BUCKET);
comparision_name, schema_name,object_name and dblink_name are mandatory. If we only want to compare local schema(s) objects we can set the dblink_name parameter to null.
In my simple example I will just do that.
I will start creating two tables which are identical besides the name, in the same database schema.
create table original(col1 varchar2(30),col2 number);
Table ORIGINAL created.
insert into original values('original_value',1);
1 row inserted.
create table copy_of_original as select * from original;
Table COPY_OF_ORIGINAL created.
commit;
Commit complete.
Next I want to create a comparsion between the two tables.
begin
DBMS_COMPARISON.CREATE_COMPARISON(
comparison_name=>'my_comp',
schema_name =>'myschema',
object_name=>'original',
dblink_name=> null,
remote_schema_name=>'myschema',
remote_object_name=>'copy_of_original');
end;
ORA-23676: no eligible index on local table "MYSCHEMA"."ORIGINAL"
According to the docs, to create a valid comparision.
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, or CHAR datatype column
- A composite index that only includes number, timestamp, interval, DATE, VARCHAR2, or CHAR columns.
- Each column in the composite index must either have a NOT NULL constraint or be part of the primary key.
But also
The index columns in a comparison must uniquely identify every row involved in a comparison.
The following constraints satisfy this requirement:
- A primary key constraint
- A unique constraint on one or more non-NULL columns
So I my case I have to add primary keys constraints to my tables.
alter table original add constraint pk_original primary key(col1);
Table ORGINAL altered.
alter table copy_of_original add constraint pk_copy_of_original primary key(col1);
Table COPY_OF_ORGINAL altered.
begin
DBMS_COMPARISON.CREATE_COMPARISON(
comparison_name=>'my_comp',
schema_name =>'myschema',
object_name=>'original',
dblink_name=> null,
remote_schema_name=>'myschema',
remote_object_name=>'copy_of_original');
end;
PL/SQL procedure successfully completed.
So now I have created a comparison called my_comp which compares the table “original” and “copy_of_original”.
The next step is to run DBMS_COMPARISON.COMPARE
DECLARE
consistent BOOLEAN;
scan_info DBMS_COMPARISON.COMPARISON_TYPE;
BEGIN
consistent := DBMS_COMPARISON.COMPARE
( comparison_name => 'my_comp'
, scan_info => scan_info
, perform_row_dif => TRUE
);
DBMS_OUTPUT.PUT_LINE('Scan ID: '||scan_info.scan_id);
IF consistent=TRUE THEN
DBMS_OUTPUT.PUT_LINE('No differences were found.');
ELSE
DBMS_OUTPUT.PUT_LINE('Differences were found.');
END IF;
END;
/
Scan ID: 10
No differences were found.
PL/SQL procedure successfully completed..
No differences, obviously . Let’s update the tabel “copy_of_original”, and rerun the scan.
update copy_of_original set col1='copy_of_original';
1 row updated.
commit;
Commit complete.
DECLARE
consistent BOOLEAN;
scan_info DBMS_COMPARISON.COMPARISON_TYPE;
BEGIN
consistent := DBMS_COMPARISON.COMPARE
( comparison_name => 'my_comp'
, scan_info => scan_info
, perform_row_dif => TRUE
);
DBMS_OUTPUT.PUT_LINE('Scan ID: '||scan_info.scan_id);
IF consistent=TRUE THEN
DBMS_OUTPUT.PUT_LINE('No differences were found.');
ELSE
DBMS_OUTPUT.PUT_LINE('Differences were found.');
END IF;
END;
/
Scan ID: 12
Differences were found.
Scan id 12 is the parent scan id for every other scan in THIS specified comparison. Each time the DBMS_COMPARISON.COMPARE function is executed, one or more new scans may be performed, but with one common parent scan id.
In the toolbox we have several dictonary views that are available. Depending on your needs and priviliges of course.
- USER_COMPARISON
- USER_COMPARISON_COLUMNS
- USER_COMPARISON_SCAN_SUMMARY
- USER_COMPARISON_COLUMNS
- USER_COMPARISON_ROW_DIF
- USER_COMPARISON_SCAN
- USER_COMPARISON_SCAN_VALUES
To show the difference between the two tables for scan id 12
select
c.column_name,
r.index_value,
decode(r.local_rowid, NULL, 'No', 'Yes') local_rowid,
decode(r.remote_rowid, NULL, 'No', 'Yes') remote_rowid
from
user_comparison_columns c,
user_comparison_row_dif r,
user_comparison_scan s
where c.comparison_name = 'MY_COMP'
and r.scan_id = s.scan_id
and s.parent_scan_id = 12
and r.status = 'DIF'
and c.index_column = 'Y'
and c.comparison_name = r.comparison_name;

Here we see that the remote value for COL1 is “copy_of_original” and the local value is “original_value”. There is of course many ways to compare data in Oracle, but this was a new way for me.
DBMS_COMPARISON.CONVERGE gives the possibilty to make the data consistent between two source. That’s another post.
If you are planning to use DBMS_COMPARISON on a bigger scale, I would recommend reading about potential hash collisions.
Over & Out
Leave a comment