Для сред репликации типичным является разделение таких объектов базы данных Oracle, как таблицы и индексы. Эти объекты известны как разделяемые объекты базы данных, поскольку несколько баз данных совестно используют их между собой. Разделяемые объекты базы данных обычно применяются материализованными представлениями и компонентами Oracle Streams, которые поддерживают копии одних и тех же таблиц и прочих объектов в нескольких базах данных. Среды репликации подобного рода стараются хранить общие объекты базы в разных местах в синхронизированном виде. Однако нередко происходит рассинхронизация таких объектов, и тогда таблица в отличающимся количеством строк и/или разными данными сравнивается c такой же таблицей в другой базе. Подобные расхождения данных, вызванные сетевыми проблемами, ошибками пользователей, изменениями в конфигурации, проблемами обновления материализованных представлений и т. д., могут помешать фиксации изменений в базе данных или успешной передаче их другим базам, которые связаны в общую среду репликации.
В Oracle Database 12c и 11g предусмотрен пакет DBMS_COMPARISON, который позволяет сравнивать объекты в различных базах. Если процесс сравнения показывает существенные расхождения между двумя базами данных, с помощью этого же пакета можно свести данные в обеих базах, так что они становятся идентичными. Сравнивать и сводить можно следующие типы объектов:
- таблицы;
- представления на одиночных таблицах;
- материализованные представления;
- синонимы перечисленных трех типов объектов.
Чуть позже будет приведен пример сравнения двух одноименных таблиц в разных базах данных, состоящих из одного и того же набора столбцов. Можно также сравнивать и разноименные таблицы, а также таблицы с разными столбцами, если только столбцы в двух таблицах будут одного и того же типа. Вдобавок можно сравнивать (и сводить) подмножества столбцов и строк вместо целых таблиц и материализованных представлений.
Сравнение данных на примере таблиц
В следующем примере мы сравним простой разделенный объект базы данных (таблицу employees), который принадлежит схеме пользователя HR. Чтобы наглядно продемонстрировать сведение данных, сначала мы изменим данные в трех строках разделенного объекта (таблице departments) удаленной базы данных. Затем с помощью пакета DBMS_COMPARE мы сравним две таблицы в двух базах, после чего воспользуемся им же для объединения отличий, чтобы две таблицы снова стали синхронизированными.
Единственное требование, которое должно быть удовлетворено при использовании пакета DBMS_COMPARE, состоит в том, чтобы сравниваемые таблицы имели, по крайней мере, один столбец, используемый в качестве индекса, по которому можно идентифицировать запись. Такой индексный столбец должен уникально идентифицировать каждую строку, участвующую в сравнении, в том смысле, что индекс должен быть либо первичным, либо уникальным ключом на столбце, не допускающем NULL-значения. В противном случае пакет не сможет сравнить два объекта. Таблица employee имеет столбец первичного ключа в обеих базах данных, так что здесь все в порядке.
1. Создадим связь первичной базы данных (or11) с вторичной базой (tenner). В примере в качестве владельца связи базы данных выступает пользователь system; это гарантирует наличие достаточных привилегий для выполнения процедур пакета DBMS_COMPARISON, а также для доступа и модификаций таблиц в обеих базах. Удаленная база данных называется tenner, поэтому так же мы назовем и ее связь из первичной базы данных or11.
SQL> create database link tenner connect to system identified by sammyy1 using 'tenner'; Database link created. SQL>
Следующий шаг — получение расхождений между данными идентичных таблиц в двух базах данных.
2. Во вторичной базе проведем некоторые изменения в таблице hr.employees, чтобы данные отличались от данных той же таблицы из первичной базы:
SQL> delete from hr.employees where ename='MILLER'; 1 row deleted. SQL> update hr.employees set sal=10000 where ename='FORD'; 1 row updated. SQL> insert into hr.employees values (9999,'ALAPATI','DBA',7792,'20-JUN-00',50000,10000,30); 1 row created. SQL> commit; Commit complete. SQL>
Обеспечив различие таблиц hr.employees в двух базах, можно запустить процедуру CREATE_COMPARISON для обнаружения этих различий.
3. Выполним сравнение таблицы hr.employees с одноименной таблицей второй базы, запустив процедуру CREATE_COMPARISON, как показано ниже:
SQL> begin 2 dbms_comparison.create_comparison( 3 comparison_name => 'compare1', 4 schema_name => 'hr', 5 object_name => 'employees', 6 dblink_name => 'tenner'); 7* end; SQL> / PL/SQL procedure successfully completed. SQL>
4. Выполним функцию COMPARE, чтобы посмотреть, нашла ли процедура CREATE_COMPARISON различия в двух таблицах:
SQL> declare 2 consistent boolean; 3 scan_info dbms_comparison.comparison_type; 4 begin 5 consistent := dbms_comparison.compare( 6 comparison_name => 'comp1', 7 scan_info => scan_info, 8 perform_row_dif => TRUE); 9 DBMS_OUTPUT.PUT_LINE('Scan ID: '||scan_info.scan_id); 10 IF consistent=TRUE THEN 11 DBMS_OUTPUT.PUT_LINE('No differences were found.'); 12 ELSE 13 DBMS_OUTPUT.PUT_LINE('Differences were found.'); 14 end if; 15* end; SQL> / Scan ID: 4 Differences were found. PL/SQL procedure successfully completed. SQL>
Функция compare использует Scan ID, равный 4, и печатает предложение “Differences were found” (Различия обнаружены).
5. Поскольку различия есть, можно запустить следующий запрос, использующий представления DBA_COMPARISON и DBA_COMPARISON_SCAN_SUMMARY, чтобы узнать, сколько различий было обнаружено при сравнении таблиц:
SQL> select c.owner, 2 c.comparision_name, 3 c.schema_name, 4 c.object_name, 5 s.current_diff_count 6 from dba_comparison , dba_comparison_scan_summary s 7 where c.comparison_name = s.comparison_name and 8 c.owner = s.owner and 9 s.scan_id = 1; OWNER COMP_NAME SCHEMA_NAME OBJECT_NAME CURRENT_DIF_COUNT ------- --------- ------------- ------------ ----------------- SYSTEM COMP1 HR EMPLOYEES 3 SQL>
Столбец current_diff_count из DBA_COMPARISON_SCAN_SUMMARY показывает, что есть три строки, отличающиеся между таблицей hr.employees в базе данных or11 и таблицей hr.employees в базе данных tenner. Различие может быть обусловлено тем, что некоторая строка присутствует в одной базе, но отсутствует в другой, или же одна и та же строка в двух базах содержит разные данные.
Синхронизация таблиц и других данных
Поскольку обнаружены расхождения между локальной и удаленной базами данных, необходимо синхронизировать таблицы hr.employees в двух базах, чтобы они содержали идентичные данные. Это делается с помощью процедуры CONVERGE из пакета DBMS_COMPARISON, как описано ниже.
1. Подключитесь к удаленной базе данных из локальной как пользователь system, который является владельцем ранее созданной связи базы данных:
$ sqlplus sytem/sammyy1@or11 SQL>
2. Выполните процедуру CONVERGE из пакета DBMS_COMPARISON для синхронизации данных между двумя базами:
SQL> declare 2 scan_info DBMS_COMPARISON.COMPARISON_TYPE; 3 begin 4 DBMS_COMPARISON.CONVERGE( 5 comparison_name => 'comp1', 6 scan_id => 4, 7 scan_info => scan_info, 8 converge_options => DBMS_COMPARISON.CMP_CONVERGE_LOCAL_WINS); 9 DBMS_OUTPUT.PUT_LINE('Local Rows Merged: '||scan_info.loc_rows_merged); 10 DBMS_OUTPUT.PUT_LINE('Remote Rows Merged: '||scan_info.rmt_rows_merged); 11 DBMS_OUTPUT.PUT_LINE('Local Rows Deleted: '||scan_info.loc_rows_deleted); 12 DBMS_OUTPUT.PUT_LINE('Remote Rows Deleted: '||scan_info.rmt_rows_deleted); 13* end; SQL> / Local Rows Merged: 0 Remote Rows Merged: 2 Local Rows Deleted: 0 Remote Rows Deleted: 1 PL/SQL procedure successfully completed. SQL>
В этом примере мы решили заменить данные таблицы hr.employees в удаленной базе данными из таблицы hr.employees локальной базы. Таким образом, в качестве опции сведения используется cmp_converge_local_wins, а это означает, что данные из локальной базы получат преимущество перед данными из удаленной базы. Однако можно было бы выбрать и обратный путь, указав cmp_converge_remote_wins — тогда данные таблицы из удаленной базы заменили бы данные таблицы локальной базы.
Процедура converge может модифицировать или удалить данные из одной базы данных, чтобы синхронизировать данные в обеих базах Oracle. Вывод, печатаемый после завершения процедуры converge, демонстрирует, что две строки в удаленной базы были слиты (merged), потому что они отличались от тех же строк в локальной базе. Слияние в данном случае означает, что строки локальной таблицы заменяют строки в удаленной таблице. Одна строка отражена в Remote Rows Deleted. Это строка, которая была найдена в удаленной базе данных, но отсутствовала в локальной. Поскольку мы решили, что данные удаленной базы должны совпадать с данными базы локальной, процедура converge удаляет строку из удаленной базы данных. Предполагая, что никаких других изменений во время синхронизации не произошло, теперь две таблицы в локальной и удаленной базах данных полностью синхронизированы.
Обратите внимание, что можно также сравнивать и сливать различные типы объектов двух баз данных. Например, можно сравнить и слить таблицу в одной базе с материализованным представлением в другой.