This article is in English Working with the DB Dumps
Для работы с дампами БД следует пользоваться специальным скриптом dump.sh
, который устанавливается при помощи deb пакета hydra-utils.
Этот пакет совместим с операционными системами Debian 9
и ниже. Для операционной системы Oracle Linux необходимо использовать отдельный Docker-
контейнер.
У скрипта для работы с дампами БД существуют следующие варианты запуска:
- export — снятие дампа. Дамп снимается в директорию для дампов, установленную в БД (как правило, это
/var/oradata/dumps
). - drop — очистка. Перед очисткой следует обязательно убедиться, что БД не является промышленной.
- import — загрузка дампа в БД. Перед загрузкой дампа обязательно следует выполнить очистку. Дамп поднимается из директории для дампов, установленной в БД (как правило, это
/var/oradata/dumps
). После импортирования флаг «Признак промышленной базы данных» сбрасывается.
Дополнительные параметры вызова скрипта:
- -i — название БД
- -o — название схемы
- -p — пароль пользователя AIS_NET
- -f — название дампа (файла с дампом)
- -s — отказ от предупреждающего сообщения при очистке БД
Пример использования dump.sh при нативной установке hydra-utils
При установке hydra-utils скрипт снятия дампов устанавливаются в следующую директорию - /opt/hydra/oracle/scripts
. Скрипт обязательно следует вызвать под пользователем oracle с инициализированным окружением. Инициализировать окружение для пользователя oracle с помощью sudo можно выполнить следующим образом:
sudo -u oracle -i
Пример вызова скрипта для переноса дампа БД с hydra на hydra2:
Снятие дампа с hydra:
/opt/hydra/oracle/scripts/dump.sh -i hydra -p password -f hydra_dump export
Очистка hydra2:
/opt/hydra/oracle/scripts/dump.sh -i hydra2 -p password drop
Поднятие дампа на hydra2:
/opt/hydra/oracle/scripts/dump.sh -i hydra2 -p password -f hydra_dump import
Во время импорта дампа в новую базу возможны ошибки следующего вида:
Failing sql is: GRANT SELECT ON "AIS_NET"."SR_V_GOOD_SERVS" TO "NET_GOODS" ORA-39083: Object type OBJECT_GRANT failed to create with error: ORA-01917: user or role 'NET_GOODS' does not exist
Эти ошибки не являются критичными, т.к. скрипт экспорта выгружает только схему AIS_NET. Отсутствующие роли создаются в БД отдельным скриптом в завершающей части импорта.
Работа с дампами при помощи hydra-utils в Docker
Использование контейнера Docker
возможно только для операционных систем с ядром Linux
версии 4 или выше.
Алгоритм установки hydra-utils
следующий:
Создать директории для конфигурационных файлов
sudo mkdir /etc/hydra/hydra-utils
Создать
docker-compose.yml
в новой директории:
Для СУБД Oracle 11 необходимо использовать следующийdocker-compose.yml
:/etc/hydra/hydra-utils/docker-compose.ymlversion: '3.7' services: hydra-utils: container_name: hydra-utils image: docker.dl.latera.ru:5000/hydra-utils:11g network_mode: "host" environment: - TZ=${TZ} - ORACLE_HOME=${ORACLE_HOME} volumes: - /u01/app/oracle/product/11g:/u01/app/oracle/product/11g:ro - /u01/app/oracle/product/11g/network/admin/tnsnames.ora:/app/tnsnames.ora:ro
Для Oracle 19:/etc/hydra/hydra-utils/docker-compose.ymlversion: '3.7' services: hydra-utils: container_name: hydra-utils image: docker.dl.latera.ru:5000/hydra-utils:latest network_mode: "host" environment: - TZ=${TZ} volumes: - /u01/app/oracle/product/19c/network/admin/tnsnames.ora:/app/tnsnames.ora
TZ
- временная зона сервера. Значение переменной окружения может быть задано вручную, либо в/etc/environment
. Например:Значение переменной TZTZ="Asia/Krasnoyarsk"
ORACLE_HOME
- каталог с установленным Oracle. Задано в/etc/environment
.После создания файлов конфигурации необходимо перейти в директорию и установить образ:
Установка образа контейнераcd /etc/hydra/hydra-utils/ sudo docker-compose pull
Пример вызова скриптов из контейнера для переноса дампа БД с hydra
на hydra2
(для Oracle 19 вместо hydra-utils нужно вызывать hydra-utils-19с)
):
Снятие дампа с hydra:
sudo docker-compose -f /etc/hydra/hydra-utils/docker-compose.yml run --rm hydra-utils dump.sh -i hydra -p password -f hydra_dump export
Очистка hydra2:
sudo docker-compose -f /etc/hydra/hydra-utils/docker-compose.yml run --rm hydra-utils dump.sh -i hydra2 -p password drop
Поднятие дампа на hydra2:
sudo docker-compose -f /etc/hydra/hydra-utils/docker-compose.yml run --rm hydra-utils dump.sh -i hydra2 -p password -f hydra_dump import
DDL
В ходе снятия дампа не должны выполняться DDL выражения, в том числе TRUNCATE и очистка очередей, иначе снятие дампа завершится с ошибкой ORA-01466: unable to read data - table definition has changed
Примечание
Так как процедура снятия резервных копий с помощью утилиты expdp (скрипт dump.sh
) является достаточно ресурсоемкой, снимать резервные копии БД рекомендуется в ночное время в часы наименьшей нагрузки на сервер (как правило, с 2-х до 4-х часов ночи).
Примечание 2
При выполнении любого drop (даже отдельных схем) все открытые соединения с базой будут принудительно завершены
Примечание 3
После выполнения поднятия дампа необходимо проверить лог импорта (файл с суффиксом _impdp.log в каталоге с дампом) на наличие ошибок
Примечание 4
При копировании дампа на внешнее хранилище необходимо копировать и лог экспорта (файл с суффиксом _expdp.log в каталоге с дампом)
Примечание 5
Новые профили пользователей, отличные DEFAULT
, не сохранятся при снятии дампов. Это происходит только при экспорте полного бекапа со всей БД. Подробнее: Export and Import Modes
Полный список команд для получения DDL кастомных профилей можно получить при помощи следующего SQL запроса:
SELECT DBMS_METADATA.GET_DDL('PROFILE',PROFILE) FROM DBA_USERS WHERE PROFILE != 'DEFAULT' GROUP BY PROFILE;
Для их автоматического резервирования рекомендуется использовать RMAN бекапы.
Отменить процесс экспорта/импорта дампа можно с помощью CTRL-C
и команды kill_job
:
... . . exported "AIS_NET"."SS_JOB_LOGS" 635.2 MB 1550063 rows . . exported "AIS_NET"."SD_PROCESSING_REQUESTS_T" 563.8 MB 7204 rows . . exported "AIS_NET"."SD_MV_DOCUMENTS" 479.7 MB 3247473 rows ^C Export> kill_job Are you sure you wish to stop this job ([yes]/no): yes
Действия после поднятия дампа
Выполнять под пользователем БД AIS_NET
Контроль невалидных объектов
После поднятия дампа необходимо убедиться что в базе данных нет невалидных объектов.
Для этого необходимо выполнить скрипт компилляции
DECLARE ch_AlterTypes VARCHAR2(1) := 'N'; num_MaxRetries NUMBER := 0; num_Counter NUMBER := 0; -- num_Retries NUMBER; PROCEDURE TRY_TO_ALTER_TYPE( vch_VC_TYPE_NAME IN ALL_OBJECTS.OBJECT_NAME%TYPE) IS num_Count NUMBER; BEGIN SELECT COUNT(*) INTO num_Count FROM ALL_OBJECTS WHERE OBJECT_NAME = vch_VC_TYPE_NAME AND OBJECT_TYPE = 'TYPE'; IF num_Count > 0 THEN EXECUTE IMMEDIATE 'ALTER TYPE "' || vch_VC_TYPE_NAME || '" COMPILE'; END IF; END TRY_TO_ALTER_TYPE; BEGIN IF ch_AlterTypes = 'Y' THEN TRY_TO_ALTER_TYPE('equipment_bind'); TRY_TO_ALTER_TYPE('equipment_binds'); TRY_TO_ALTER_TYPE('HYDRA_ANYDATA'); TRY_TO_ALTER_TYPE('HYDRA_ANYDATA_TABLE'); TRY_TO_ALTER_TYPE('application_context'); TRY_TO_ALTER_TYPE('deferred_task'); TRY_TO_ALTER_TYPE('command_result'); TRY_TO_ALTER_TYPE('command_results'); TRY_TO_ALTER_TYPE('command'); TRY_TO_ALTER_TYPE('commands'); TRY_TO_ALTER_TYPE('profile_attribute'); TRY_TO_ALTER_TYPE('profile_attributes'); TRY_TO_ALTER_TYPE('profile'); TRY_TO_ALTER_TYPE('profiles'); TRY_TO_ALTER_TYPE('sys_msg_line'); TRY_TO_ALTER_TYPE('sys_msg_lines'); TRY_TO_ALTER_TYPE('system_message'); TRY_TO_ALTER_TYPE('system_messages'); TRY_TO_ALTER_TYPE('service'); TRY_TO_ALTER_TYPE('services_list'); TRY_TO_ALTER_TYPE('account_services'); TRY_TO_ALTER_TYPE('LOG_MESSAGE'); END IF; -- Выбираем список объектов FOR rl_Object IN ( SELECT OWNER, OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS A WHERE OBJECT_TYPE IN ('PACKAGE', 'PACKAGE BODY', 'TRIGGER', 'VIEW') AND OWNER = 'AIS_NET' AND STATUS = 'INVALID' ORDER BY OBJECT_TYPE, OBJECT_NAME) -- Движение по списку LOOP num_Retries := 0; num_Counter := num_Counter + 1; <<retry>> -- Компилим объект BEGIN -- Разные команды для пакетов ХП и остальных типов объектов IF rl_Object.OBJECT_TYPE = 'PACKAGE BODY' THEN EXECUTE IMMEDIATE 'ALTER PACKAGE "' || rl_Object.OWNER || '"."' || rl_Object.OBJECT_NAME || '" COMPILE BODY'; ELSE EXECUTE IMMEDIATE 'ALTER ' || rl_Object.OBJECT_TYPE || ' "' || rl_Object.OWNER || '"."' || rl_Object.OBJECT_NAME || '" COMPILE'; END IF; EXCEPTION WHEN others THEN IF num_Retries < num_MaxRetries THEN num_Retries := num_Retries + 1; GOTO Retry; ELSE DBMS_OUTPUT.PUT_LINE('Ошибка: '|| rl_Object.OBJECT_TYPE || ' ' || rl_Object.OWNER || '.' || rl_Object.OBJECT_NAME); END IF; END; END LOOP; DBMS_OUTPUT.PUT_LINE('Total processed: ' || num_Counter); IF ch_AlterTypes = 'Y' THEN SYS.FIX_HYDRA_OBJECT_TYPES; END IF; END; /
И проверить наличие невалидных объектов
SELECT OWNER, OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS A WHERE OBJECT_TYPE IN ('PACKAGE', 'PACKAGE BODY', 'TRIGGER', 'VIEW') AND OWNER = 'AIS_NET' AND STATUS = 'INVALID' ORDER BY OBJECT_TYPE, OBJECT_NAME;
В случае, если в базе есть невалидные объекты, это может быть вызвано дефектом СУБД Oracle Bug 18881811 - Data Pump Import of Wrapped PLSQL Corrupts the Body
Для устранения дефекта необходимо применить Oracle патч и повторить действия по разворачиванию дампа.
Исключением могут быть пакеты с префиксом MI_ — ядро приложения миграции (если данные объекты не используются).
Анализ БД
Перед началом использования БД необходимо выполнить полный анализ БД.
Для этого необходимо выполнить скрипт, приведенный ниже, либо при помощи hydra-utils
sudo docker-compose -f /etc/hydra/hydra-utils/docker-compose.yml run --rm hydra-utils dump.sh -i hydra2 script SQL script name to execute (separate with comma, if many): analyze_db_full
Следует учесть что анализ БД может занимать весьма продолжительное время, поэтому рекомендуется выполнять его напрямую на сервере из sqlplus с использованием оконного менеджера, например screen (это позволит скрипту доработать даже в случае неожиданного обрыва связи с компьютером администратора)
DECLARE num_N_JOB_ID NUMBER := -101; -- ch_Invalidate SS_PARVALUES.C_FLAG_VALUE%TYPE; ch_StaleOnly SS_PARVALUES.C_FLAG_VALUE%TYPE; num_AnalyzePercent SS_PARVALUES.N_VALUE%TYPE; BEGIN DBMS_STATS.SET_GLOBAL_PREFS('NO_INVALIDATE', 'FALSE'); -- Сохранение текущих параметров num_AnalyzePercent := SS_PARS_PKG_S.GET_N_VALUE_BY_CODE( vch_VC_CODE => 'PAR_JobAnalyzeSchema_AnalyzePercent', num_N_JOB_ID => num_N_JOB_ID); ch_StaleOnly := SS_PARS_PKG_S.GET_C_FLAG_VALUE_BY_CODE( vch_VC_CODE => 'PAR_JobAnalyzeSchema_StaleOnly', num_N_JOB_ID => num_N_JOB_ID); ch_Invalidate := SS_PARS_PKG_S.GET_C_FLAG_VALUE_BY_CODE( vch_VC_CODE => 'PAR_JobAnalyzeSchema_InvalidateCursors', num_N_JOB_ID => num_N_JOB_ID); -- Установка нужных параметров SS_PARS_PKG.SS_PARVALUES_PUT( num_N_PAR_ID => SS_PARS_PKG_S.GET_PAR_ID_BY_CODE( vch_VC_CODE => 'PAR_JobAnalyzeSchema_AnalyzePercent', num_N_JOB_ID => num_N_JOB_ID), num_N_SUBJECT_ID => NULL, num_N_APPLICATION_ID => NULL, num_N_VALUE => 100, num_N_JOB_ID => num_N_JOB_ID); SS_PARS_PKG.SS_PARVALUES_PUT( num_N_PAR_ID => SS_PARS_PKG_S.GET_PAR_ID_BY_CODE( vch_VC_CODE => 'PAR_JobAnalyzeSchema_StaleOnly', num_N_JOB_ID => num_N_JOB_ID), num_N_SUBJECT_ID => NULL, num_N_APPLICATION_ID => NULL, ch_C_FLAG_VALUE => 'N', num_N_JOB_ID => num_N_JOB_ID); SS_PARS_PKG.SS_PARVALUES_PUT( num_N_PAR_ID => SS_PARS_PKG_S.GET_PAR_ID_BY_CODE( vch_VC_CODE => 'PAR_JobAnalyzeSchema_InvalidateCursors', num_N_JOB_ID => num_N_JOB_ID), num_N_SUBJECT_ID => NULL, num_N_APPLICATION_ID => NULL, ch_C_FLAG_VALUE => 'Y', num_N_JOB_ID => num_N_JOB_ID); COMMIT; -- Подготовка к выполнению задания вручную SS_JOBS_PKG.MANUAL_START_JOB(num_N_JOB_ID); -- Выполнение задания в текущей сессии SS_JOBS_PKG.RUN_JOB( num_N_JOB_ID => num_N_JOB_ID, ch_C_REASON => 'M'); DBMS_STATS.SET_GLOBAL_PREFS('NO_INVALIDATE', 'DBMS_STATS.AUTO_INVALIDATE'); -- Возврат сохраненных параметров SS_PARS_PKG.SS_PARVALUES_PUT( num_N_PAR_ID => SS_PARS_PKG_S.GET_PAR_ID_BY_CODE( vch_VC_CODE => 'PAR_JobAnalyzeSchema_AnalyzePercent', num_N_JOB_ID => num_N_JOB_ID), num_N_SUBJECT_ID => NULL, num_N_APPLICATION_ID => NULL, num_N_VALUE => num_AnalyzePercent, num_N_JOB_ID => num_N_JOB_ID); SS_PARS_PKG.SS_PARVALUES_PUT( num_N_PAR_ID => SS_PARS_PKG_S.GET_PAR_ID_BY_CODE( vch_VC_CODE => 'PAR_JobAnalyzeSchema_StaleOnly', num_N_JOB_ID => num_N_JOB_ID), num_N_SUBJECT_ID => NULL, num_N_APPLICATION_ID => NULL, ch_C_FLAG_VALUE => ch_StaleOnly, num_N_JOB_ID => num_N_JOB_ID); SS_PARS_PKG.SS_PARVALUES_PUT( num_N_PAR_ID => SS_PARS_PKG_S.GET_PAR_ID_BY_CODE( vch_VC_CODE => 'PAR_JobAnalyzeSchema_InvalidateCursors', num_N_JOB_ID => num_N_JOB_ID), num_N_SUBJECT_ID => NULL, num_N_APPLICATION_ID => NULL, ch_C_FLAG_VALUE => ch_Invalidate, num_N_JOB_ID => num_N_JOB_ID); COMMIT; END; /