СТАТЬЯ
09.11.00

Тиражирование данных из одной базы
в другую – в Oracle очень просто

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

Начнем с того, что утверждение, составляющее заголовок, в общем, ложно. Однако существующие диспропорции между эксплуатационными характеристиками локальных сетей и линий связи с ними, отягченные требованиями приложения, вынуждают часто создавать отдельные локальные сервера БД и, более того, дублировать на них часть данных “из центра”. (Это лишь одна причина, по которой тиражирование данных становится единственным техническим решением; есть и другие; но, во-первых, эта причина – важнейшая, а во-вторых, систематичное рассмотрение проблемы не составляет цель этой заметки).

Как часто бывает в Oracle (а может и не только в Oracle ?) идея, звучащая в общем просто, при реализации обрастает таким количеством технических деталей и ухищрений, что увидев все эти “навороты”, разработчик твердо решает связываться с ними только в случае полной безвыходности. Но и тогда приходится с чего-то начинать. А начинать лучше с простого. К счастью, построить работающий пример тиражирования в Oracle, прозрачный для понимания новичка, вполне возможно. Цель нижеследующего текста – доказать это.

Начальные условия

Пусть имеются две работающие базы данных. Например, их можно запустить на одном компьютере. У себя на занятиях я пользуюсь именами TEACHER и TEACHER1, и эти названия баз данных буду употребляться далее. Для базы TEACHER заведена внешняя связь под названием MYTEACHER. Проще всего завести ее в Net8 Assistant.

Мы намереваемся завести в схеме SCOTT БД TEACHER1 таблицу, являющуюся копией таблицы SCOTT.DEPT базы TEACHER.

Дальнейший текст “проигран” на версии сервера 8.1.6, управляющего обеими базами. Поскольку некоторые детали организации тиражирования в версии 7 отличны от версии 8, в тексте будут сделаны необходимые оговорки.

Одностороннее тиражирование шаг за шагом

Для удобства можно открыть два консольных окошка с SQL*Plus: первое для работы с БД TEACHER, а второе – с TEACHER1.

  1. В первом окошке создадим так называемый “журнал изменений таблицы DEPT”, то есть служебную таблицу, в которой автоматически будут отражаться все изменения в таблице SCOTT.DEPT (вставки, модификации, удаления). Для этого сначала выдадим от имени SYS:
 SQL> GRANT CREATE SNAPSHOT LOG TO scott;
  Grant succeeded.
  А затем от имени SCOTT:
  SQL> CREATE SNAPSHOT LOG ON dept WITH PRIMARY KEY;
  Materialized view log created.
  Комментарий по поводу терминологии ниже.
  1. Во втором окошке выдадим от имени SYS
SQL> GRANT CREATE SNAPSHOT TO scott;
  Grant succeeded.
  SQL> CREATE PUBLIC DATABASE LINK teacher 
 CONNECT TO scott IDENTIFIED BY tiger USING ‘myteacher’;
  Database link created.

Теперь нужно посмотреть значение init-параметра job_queue_processes на вашем сервере. Быстрее всего это сделать командой SQL*Plus show parameter job. Если оно 0, то нужно редактором текста проставить в файле INIT.ORA для TEACHER job_queue_processes = 1, сохранить файл и перезапустить систему. (Если все происходит на одной машине, пожалуйста, не ошибитесь с базами!)

  1. Войдем во втором окошке как SCOTT. Проверим для верности, есть ли связь с тезкой из базы TEACHER в соседнем окошке:
SQL> SELECT * FROM dept@teacher;
   DEPTNO DNAME LOC
   ---------- -------------- ------------- 
10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON 4 rows selected. (Должны выдаться отделы из демонстрационного примера соседней базы). Теперь можно набрать: SQL> CREATE SNAPSHOT deptcopy BUILD IMMEDIATE REFRESH FAST START WITH SYSDATE NEXT SYSDATE + 1/1440 WITH PRIMARY KEY AS SELECT * FROM dept@tech; Materialized view created.
  1. Перейдем в первое окошко и от имени SCOTT наберем:
SQL> INSERT INTO dept VALUES(60, 'MARKETING','TOKYO');
   1 row created.
   SQL> COMMIT;
  1. Вернемся во второе окошко. Передохнем с минуту, и выдадим от имени SCOTT:
SQL> SELECT * FROM deptcopy;
   DEPTNO DNAME LOC
   ---------- -------------- -------------
   10 ACCOUNTING NEW YORK
   20 RESEARCH DALLAS
   30 SALES CHICAGO
   40 OPERATIONS BOSTON
   60 MARKETING TOKYO
   5 rows selected.
   … Что и требовалось получить !

Общее пояснение

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

Для старшей базы выдается команда CREATE SNAPSHOT LOG. По этой команде:

Для младшей базы выдается команда CREATE SNAPSHOT, по которой автоматически создаются:

Таким образом, общая техника выполнения тиражирования становится ясной: в старшей базе создается триггер, заносящий все изменения в тиражируемой таблице в специальную журнальную таблицу, а в младшей базе периодически запускается встроенная процедура, обращающаяся по связи (link) за данными в старшую базу, и вносящая необходимые изменения в реплику.

Маленькое терминологическое отступление

Реплика, то есть таблица, воспроизводящая изменения данных в других таблицах (и, возможно, в базах), в версии 7 Oracle называется snapshot. (Встречаются другие переводы на русский язык, например, буквальный: “фотографический снимок”). В версии 8 это название для совместимости сохранено, однако появилось и более общее: materialized view, “материализованное представление”. Механизм materialized view может много чего другого по сравнению со snapshot, например, делать автоматическую подмену SQL-запроса на другой, более эффективно обрабатываемый, если это возможно. (Только не ожидайте, пожалуйста, прозрачной для понимания технической реализации materialized view!). Всякий (-ая) snapshot является materialized view, но не всякое materialized view является snapshot.

Введя на замену старому новое понятие, фирма Oracle, как часто с ней бывает, не сумела до конца “выкорчевать” первое, и оно регулярно возникает в разных местах – в сообщениях, названии процессов и так далее. Пугаться не надо, к этому приходится привыкнуть.

Комментарий к организации тиражирования

Теперь стоит дать краткий комментарий конкретно относительно проделанных только что действий.

Общий комментарий

Однонаправленное тиражирование “старший – младший узел” самое простое по организации и сопровождению и не требует наличия в вашей системе Advanced Replication Option. Требуется наличие пакетов DBMS_SNAPSHOT и DBMS_REFRESH, но они обычно устанавливаются при создании базы данных в результате прогона catproc.sql, вызывающего, в свою очередь, dbmssnap.sql и prvtsnap.sql.

Комментарий к начальным условиям

Имена пользователей на старшем и младшем узле вовсе не обязаны совпадать. SCOTT выбран только потому, что этот пользователь всем известен и почти всегда в базе есть (а если нет – создается одной командой в SQL*Plus).

Комментарий к шагу 1

Таблица DEPT выбрана по двум причинам: у нее есть первичный ключ (что в нашем варианте создания реплики обязательно, а вообще-то, необязательно), и она непуста и мала, что удобно для иллюстраций.

Фраза WITH PRIMARY KEY указывает на то, что ссылки из журнала на строки базовой таблицы DEPT будут делаться по ключу. Можно было бы делать и по ROWID, указав WITH ROWID (а в версии 7 это была единственная возможность), но более правильно и надежно (с точки зрения внесения изменений в приложение) организовать в журнале ссылки именно по ключу.

Комментарий к шагу 2

Системные привилегии CREATE SNAPSHOT и CREATE DATABASE LINK входят в состав роли ADM, причем вторая из них – еще и в CONNECT, IMP_FULL_DATABASE и RECOVERY_CATALOG_OWNER. Поэтому не исключено, что они у “вашего” SCOTT уже есть.

Имя создаваемой связи должно совпадать с именем базы данных, с которой налаживается взаимодействие.

Комментарий к шагу 3

В предложении CREATE SNAPSHOT фраза BUILD IMMEDIATE означает, что “первая” реплика будет построена сразу же по выдаче этого предложения.

Фраза REFRESH FAST указывает на то, что реплика будет изменяться путем применения к ней модификаций исходных данных. В противовес этому можно было бы изменять реплику путем полного ее пересоздания с нужной периодичностью. Ясно, то выбранный нами метод изменения более экономен, особенно на больших таблицах.

Фраза START WITH SYSDATE NEXT SYSDATE + 1/1440 говорит о том, что фоновый процесс SNP, заведенный на шаге 2 изменением INIT-параметра, будет привлекаться заданием (job), созданным предложением CREATE SNAPSHOT, для извлечения изменений в базовой таблице и внесения их в реплику, начиная с текущего момента и далее ежеминутно.

Фраза WITH PRIMARY KEY: раз мы ее указали при создании журнальной таблицы, то должны указать и здесь. В прочем см. аналогичный комментарий для шага 2.

По поводу запроса SELECT. Здесь он по виду самый простой, но, во-первых, можно было указать в нем отбор строк по условию WHERE и/или столбцов путем явного перечисления полей. То есть, мы вовсе не обязаны воспроизводить на младшем узле всю исходную таблицу целиком, что составляет большой плюс для разработки приложения. Более того, и во-вторых, мы не обязаны ограничиваться в этом запросе только одной базовой таблицей, и можем извлекать данные из двух и более таблиц. При планировании такого решения, правда, нелишне принять во внимание и проблемы эффективности, и, возможно, подумать над иным вариантом его реализации.

На этом шаге не мешает обратиться к USER_OBJECTS и посмотреть, что нового появилось в вашей схеме (из того, что Oracle8 считает нужным вам показать). Заметим, что DEPTCOPY – это представление, и модифицировать его самим не получится. Это – выводимая таблица только для чтения.

Комментарий к шагу 4

Не забудьте выполнить COMMIT, а то за “минуту” из следующего шага вы успеете не только кофе попить, но и пообедать.

Комментарий к шагу 5

Без комментариев. Впрочем, нет. Если по каким-то причинам процесс обновления реплики не работает (например, не работает связь), то после определенного числа безуспешных попыток задание на обновление реплики будет помечено как “неработающее” (broken) и перестанет активизироваться раз в минуту. Впрочем, это уже выходит за рамки простейшего примера, в котором все должно быть нормально, и здесь начинаются, как говорится, “детали”.

О чем я не рассказал

О массе этих самых “деталей” – следуя назначению этой заметки. Например, о том,

Но если пример, проделанный собственными руками, вас воодушевил, то более плотное изучение вопросов построения однонаправленного тиражирования окажется для вас, чисто психологически, проще.

Если этот текст помог/не помог вам в этой задаче, или если вы просто хотите сообщить мне свои замечания, рекомендации или комментарии, я буду благодарен получить от вас письмо.

Отправьте свое мнение об этом материале его автору

Дополнительную информацию Вы можете получить в компании Interface Ltd.

Обсудить на форуме Oracle
Отправить ссылку на страницу по e-mail


Interface Ltd.

Ваши замечания и предложения отправляйте автору
По техническим вопросам обращайтесь к вебмастеру
Документ опубликован: 09.10.00