26.02.2016 0 min to read

История переноса одной базы

Category : Статьи

Перенос сервера, смена версии ПО и т.д. – занятия неизменно муторные. И вот настал тот час, когда необходимость переноса немаленькой БД на новую платформу встала во всей красе. Задача: полностью перенести БД с ORACLE 10gR2 на ORACLE 11gR2. Никаких премудростей вида RMAN в наличии не присутствует, по старинке пользуемся обычным дампом.

Первая ошибка – выбор кодировки. Точнее, эту ошибку совершили много лет назад, выбрав в качестве CHARACTER SET кодировку CL8KOI8R. А теперь попытались это исправить. Создаем новый экземпляр БД в кодировке AL32UTF8. Все прекрасно, если проект развивается “с нуля” и никаких данных еще нет. А вот перенести в таком варианте данные достаточно проблематично. Первая проблема – различие количества байт, отводящееся на символ. В обычном варианте 1 символ – 1 байт, в al32utf8 символ может занимать до 4 байт. Поэтому первое, что приходится делать, во избежание переполнения данных varchar2 определять размерность не в байтах, а в символах. Например, varchar2(1024 char). Но это еще не гарантия того, что при перекодировке какой-нибудь заковыристый символ из koi8 не перекодируется в нечто, приводящее к ошибке:

ORA-01461: can bind a LONG value only for insert into a LONG column

Такая ошибка может появляться как при попытке импорта данных, размерность которых определена в байтах – varchar2(4000 byte), что присутствует по-умолчанию, если для сессии не задан параметр NLS_LENGTH_SEMANTICS=CHAR, так и при перекодировке “проблемных” символов. При небольшом объеме данных можно искать такие места и решать проблему вручную. В нашем случае не было никакой гарантии, что удастся легко избавиться от всех последствий, поэтому следующее решение: вернуться к старой кодировке. Это тоже непросто. Чтобы поменять кодировку БД, старая кодировка должна быть подмножеством новой кодировки. Иначе появляется ошибка:

ORA-12712: new character set must be a superset of old character set

Выхода в этой ситуации 2: пересоздать базу заново или воспользоваться специальной командой ALTER DATABASE CHARACTER SET INTERNAL_USE:

connect / as sysdba
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER SYSTEM ENABLE RESTRICTED SESSION;
ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
ALTER SYSTEM SET AQ_TM_PROCESSES=0;
ALTER DATABASE OPEN;
ALTER DATABASE CHARACTER SET INTERNAL_USE CL8KOI8R;

 

Кодировка в базе меняется, НО. Данные, уже присутствовавшие в базе, не перекодируются. Т.е. после проделанной операции текст становится нечитаемым. Хотя в нашем случае потеря была невелика, т.к. из дампа сумела импортироваться только часть данных.

Теперь приступаем к переносу с самого начала. Перед тем, как импортировать структуру и данные, необходимо:

  1. подготовить необходимые табличные пространства, аналогичные использовавшимся в исходной БД;
  2. вручную создать все необходимые пользовательские роли;
  3. вручную выдать ролям все необходимые привилегии на роли;
  4. создать контексты;
  5. создать всех необходимых пользователей с соответствующими привилегиями (кроме объектных);
  6. подготовить скрипт создания публичных псевдонимов.

Если в разработанной БД используется ограничение доступа, такое как FGA (Fine Granted Access), дамп следует снимать только от имени пользователя sys (это наш случай). Даже пользователь system не может преодолеть ограничений FGA. При создании/применении дампа часто возникает вопрос: как, используя соединение от имени пользователя sys, указать и вид доступа as sysdba, и имя строки связи из tnsnames? Конструкция следующая: ‘username/password@tnsname as sysdba’

Собирая все вместе, снять дамп можно следующими командами:

  1. полный дамп
    exp 'sys@orcl as sysdba' file=expfull.dmp log=expfull.log full=y
  2. дамп отдельных схем БД
    exp 'sys@orcl as sysdba' file=exp.dmp log=exp.log owner=(user1,user2,user3)
  3. дамп отдельных таблиц заданной схемы (в этом случае экспорт запускается от имени владельца)
    exp 'user1@orcl' file=expuser1.dmp log=expuser1.log tables=(table1,table2)

Применить полученный дамп можно следующей командой:

imp 'sys@orclnew as sysdba' file=exp.dmp log=imp.log fromuser=(user1,user2,user3)

В рзультате, в новую БД переносятся таблицы, индексы, ограничения, правила FGA, триггера, представления, функции, процедуры, пакеты, типы, объектные привилегии, ссылки на БД (DB links), задания (jobs). Некоторые объекты могут быть созданы с ошибками компиляции. В этом случае их необходимо перекомпилировать (иногда требуется несколько проходов). Не переносятся публичные псевдонимы (public synonyms), контексты (contexts) и привилегии на роли. После применения дампа все это придется создавать вручную.