Тиражирование данных с обратной связью - своими руками

Источник: Interface
Владимир Пржиялковский, преподаватель УКЦ Interface Ltd.

В статье "Тиражирование данных из одной базы в другую - в Oracle очень просто" писалось о том, как организовать тиражирование данных из одних таблиц в другие, возможно в другую схему, возможно в другую базу. Достоинства и ограничения такого вида тиражирования тесно переплетены. [Достоинство: ] Это самый простой вид тиражирования, и его результат (реплика) может быть достигнут достаточно сложным SQL-запросом, то есть таблицы вовсе не обязательно воспроизводятся "один к одному"; но, [ограничение: ] в то же время такая реплика доступна только на выборку данных. Иногда же возникает необходимость вносить в растиражированные данные изменения, которые бы передавались назад, в исходные таблицы.

В таких случаях имеет смысл подумать об использовании тиражирования с обратной связью (updatable snapshots/materialized views, в терминологии Oracle).

Этот вид тиражирования более громоздок, чем одностороннее тиражирование, поскольку он

(а) требует наличия на сервере Advanced Replication Option,
(б) использует более мудреные механизмы выполнения, и
(в) несколько сложнее в администрировании.

И, тем не менее, моя цель - показать, как и в прошлой статье, что первый шаг к освоению этого вида тиражирования можно сделать без особых мук. Мы с вами сейчас организуем тиражирование с обратной связью таблицы SCOTT.DEPT из одной базы в таблицу SCOTT.DEPTC другой базы.

План действий и начальные условия

План действий таков. Сначала установим Advanced Replication Option, затем подготовим серверы к организации тиражирования и, наконец, заведем на "старшем" и на "младшем" серверах (master site и snapshot site) нужные объекты (в том числе реплику). Потом проверим, как работает организованный нами этот вид тиражирования.

Как и раньше, удобно для работы завести два консольных окошка: первое для "старшего" сервера (таблица SCOTT.DEPT), и второе - для "младшего" (таблица SCOTT.DEPTCOPY). Имя базы данных в первом окошке будет TEACHER, а во втором - TEACHER1:

 

Первое окошко

Второе окошко

Имя БД

TEACHER.CLASS

TEACHER1.CLASS

Исходная таблица

SCOTT.DEPT

-

Реплика исходной таблицы

-

SCOTT.DEPTC

Имя связи (connect string) с "парной" БД

TEACHER1SNAP

TEACHERMASTER

Оба сервера, использованные для "прокатки" примера, имели версию 8.1.6.

Установка Advanced Replication Option

Она понадобится, если это дополнение к основной поставке у вас не установлено. Выполняется она "в два прыжка": программные компоненты заводятся специальным указанием во время работы Oracle Installer, а необходимые объекты в словаре-справочнике данных создаются при создании базы. Если второго не произошло, а базу вы уже создали - дело поправимо. В первом и втором окошке нужно войти в SQL*Plus от имени SYS и запустить сценарий catrep.sql из rdbms{\//}admin. Наберитесь терпения: сценарий выполняется достаточно долго. Кроме того, размер файла с пространством SYSTEM на моей машине после установки Advanced Replication Option увеличился примерно на 20 Мб "с гаком".

Одним из следствий проработки catrep.sql будет создание в пространстве SYSTEM чудовищно большого пакета dbms_repcat, не раз помянутого ниже.

Готовим серверы и БД к тиражированию

Установка INIT-параметровдля заданий Job

Как и в прежней статье, нужно проверить значение параметров

JOB_QUEUE_PROCESSES и
JOB_QUEUE_INTERVAL 

Если значение первого параметра хотя бы на одном из ваших серверов 0 (значение по умолчанию), проставьте его в 2. Значение второго параметра по умолчанию - 60 [секунд]. Для наших целей оно вполне нормально. Не забудьте перезагрузить обе системы - сразу сейчас, или после следующего шага.

Установка глобальных имен ваших баз

Для того, чтобы дополнение Advanced Replication Option работало, обе ваши базы должны иметь глобальные имена. Попутно замечу, что Oracle рекомендует использовать глобальные имена вообще всегда, намекая на то, что в будущем это станет единственным режимом использования системы.

Нужно выставить в INIT.ORA

GLOBAL_NAMES = TRUE

(или убедиться, что так уже есть) и проставить значение домена для вашей базы. На занятиях я для домена выбираю имя CLASS, и поэтому для обоих баз ставлю

DB_DOMAIN = CLASS

У себя вы можете выбрать и составное имя, например < имя_машины >.< имя_сети >, или еще более сложное.

В каждом из двух окошек перезапускаем систему. После этого от имени SYS выдаем в первом :

ALTER DATABASE RENAME GLOBAL_NAME TO teacher.class;

и во втором :

ALTER DATABASE RENAME GLOBAL_NAME TO teacher1.class;

Установка взаимных связей

В первом окошке от имени SYS набираем:

CREATE PUBLIC DATABASE LINK teacher1.class;

Во втором окошке от имени SYS набираем:

CREATE PUBLIC DATABASE LINK teacher.class
CONNECT TO scott IDENTIFIED BY tiger USING ‘teachermaster’;

Еще одну связь заведем чуть позже, когда создадим администратора репликации.

Не помешает сразу проверить работоспособность созданных связей - в обоих окошках.

Заведение служебных пользователей

В обоих окошках следует от имени SYS завести "администратора тиражирования". Часто для такого администратора выбирают имя REPADMIN, а мы еще припишем ему такой же пароль. Выполним последовательно:

CREATE USER repadmin IDENTIFIED BY repadmin
DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp;
GRANT CREATE SESSION TO repadmin;
EXEC 
DBMS_REPCAT_ADMIN.GRANT_ADMIN_ANY_SCHEMA('REPADMIN');

Последнее предложение придаст пользователю REPADMIN набор необходимых для его работы привилегий.

Кроме того, во втором окошке, не отключаясь от SYS, заводим пользователя-"пропагатора" ("толкача") с набором необходимых ему прав:

CREATE USER proprep IDENTIFIED BY proprep
DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp;
EXEC DBMS_DEFER_SYS.REGISTER_PROPAGATOR('PROPREP');

Тут же можно дать для SCOTT права на создание снимков:

GRANT CREATE SNAPSHOT TO scott;

В этом же окошке перейдем в REPADMIN и создадим связь:

CREATE DATABASE LINK teacher.class 
  CONNECT TO repadmin IDENTIFIED BY repadmin
  USING 'teachermaster';

Не мешает удостовериться, что она функционирует

Готовим master site

В первом окошке выполняем следующее. От имени SCOTT в SQL*Plus создаем журнал для репликации таблицы DEPT:

CREATE SNAPSHOT LOG ON dept WITH PRIMARY KEY;

От имени REPADMIN в SQL*Plus создаем шаг за шагом следующее (пояснения ниже выделены серым фоном):

BEGIN
DBMS_REPCAT.CREATE_MASTER_REPGROUP( 
  gname => 'DIVISIONSGROUP', 
  group_comment => 'Created by '//USER//' on '//SYSDATE);
END;

Здесь мы создали группу репликации. В отличие от одностороннего тиражирования, в тиражировании с обратной связью нельзя тиражировать таблицы по отдельности - они обязательно должны входить в состав какой-нибудь специально созданной для этого группы.

BEGIN
DBMS_REPCAT.CREATE_MASTER_REPOBJECT( 
  sname => 'SCOTT', 
  oname => 'DEPT', 
  type => 'TABLE',
  use_existing_object => TRUE, 
  comment => 'Added by '//USER//' on '//SYSDATE, 
  copy_rows => FALSE, 
  gname => 'DIVISIONSGROUP');
END;

Здесь мы добавили в созданную только что группу репликации DIVISIONSGROUP таблицу SCOTT.DEPT.

BEGIN
DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT( 
  sname => 'SCOTT', 
  oname => 'DEPT', 
  type => 'TABLE',
  distributed => TRUE);
END;

Включив таблицу DEPT в группу репликации, мы должны вручную создать (или пересоздать, если мы переопределяли таблицу или группу) целый ряд системных объектов (триггеры, пакеты и тела), которые будут отрабатывать процедуру репликации - таковы в Oracle правила игры. Вот мы их и создали.

EXEC DBMS_REPCAT.RESUME_MASTER_ACTIVITY('DIVISIONSGROUP');

Название этой процедуры вполне объясняет ее назначение.

Все. Старший узел к репликации готов!

Готовим snapshot site

Во втором окошке выполняем следующее. От имени SCOTT создадим снимок, например так:

CREATE SNAPSHOT deptc
USING INDEX REFRESH FAST START WITH SYSDATE 
WITH PRIMARY KEY
FOR UPDATE 
AS SELECT * FROM dept@teacher.class WHERE deptno > 20;

Заметим, что возможности отбора в этом виде тиражирования сужены (что естественно), но отбирать строки возможность имеется. Частоту обновления здесь не указываем, так как она возьмется из определения группы обновления, создаваемой ниже, и будет одна для всех снимков в группе.

Затем от имени REPADMIN в SQL*Plus последовательно выдадим

BEGIN
DBMS_REPCAT.CREATE_SNAPSHOT_REPGROUP( 
  gname => 'DIVISIONSGROUP', 
  master => 'TEACHER.CLASS',
  comment => 'Created on '//SYSDATE//' by '//USER, 
  propagation_mode =>'ASYNCHRONOUS');
END;

Группа репликации на младшем узле должна именоваться так же, как и созданная выше на старшем. Синхронная репликация - это для нас поначалу слишком сильно ! Ограничимся асинхронной.

BEGIN
DBMS_REPCAT.CREATE_SNAPSHOT_REPOBJECT( 
  sname => 'SCOTT', 
  oname => 'DEPTC', 
  type => 'SNAPSHOT', 
  gname => 'DIVISIONSGROUP',
  comment => 'Created on '//SYSDATE//' by '//USER, 
  gen_objs_owner => 'REPADMIN');
END;

Добавляем созданную выше реплику SCOTT.DEPTC в созданную только что группу.

BEGIN
DBMS_REFRESH.MAKE( -
  name => 'DIVISIONSGROUP', 
  list => 'SCOTT.DEPTC', 
  next_date => SYSDATE, 
  interval => 'SYSDATE + 1/1440',
  push_deferred_rpc =>TRUE, 
  purge_option => 1, 
  parallelism => 4, 
  lax => TRUE);
END;

Тут мы создаем группу обновления. Указана частота "раз в минуту", но это только для того, чтобы проверить, как все работает, в разумные сроки. Для рабочей системы частое обновление - нагрузка на оба узла данных, так что в планировании реального, а не "игрушечного", тиражирования это нужно иметь в виду. (Немаловажен, также, и объем изменений).

BEGIN
DBMS_REFRESH.ADD ( 
  name => 'DIVISIONSGROUP', 
  list => 'SCOTT.DEPTC', 
  lax => TRUE);
END;

Добавляем наш снимок в группу обновления.

Младший узел к репликации готов !

Теперь все. Тиражирование должно работать.

Проверяем, как работает

Не знаю, как для кого, а для меня это - самая приятная часть работы. Набираем в первом окошке от имени SCOTT что-нибудь вроде

INSERT INTO DEPT VALUES (50, ‘JANITARY’,’KIEV’);

и

COMMIT;

С минуту барабаним пальцами по столу и спрашиваем во втором окошке:

SELECT * FROM deptc;

Торопиться не надо: Киев в перечне мест нахождения отделов может чуть задержаться. Увидев его в ответе, набираем тут же:

UPDATE deptc SET loc = ‘MOSCOW’;

и

COMMIT;

и ждем с минуту, пока в первом окошке не получим в ответ на

SELECT * FROM dept;

новое местонахождение службы уборки помещений.

Созданная вашими руками репликация таблицы отделов исправно выполняется как в прямом, так и в обратном направлениях. Может и не очень, но просто. И, достаточно понятно. Остальное - детали.


Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=3791