Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: В "Контроль невалидных объектов" добавила примечание о пакетах с префиксом MI_

Table of Contents


Info

This article is in English Working with the DB Dumps

Для работы с дампами БД следует пользоваться специальным скриптом dump.sh, который , как правило, располагается в /opt/hydra/oracle/scripts/dump.sh. Скрипт обязательно следует вызвать под пользователем oracle с инициализированным окружением. Инициализацию окружения для пользователя oracle с помощью sudo можно выполнить с помощью следующей команды:

Code Block
$ su - oracle

У данного скрипта для работы с устанавливается при помощи 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 можно выполнить следующим образом:

Code Block
languagebash
sudo -u oracle -i

Пример вызова скрипта для переноса дампа БД с hydra на hydra2:

  1. Снятие дампа с hydra:

    $ ./
    Code Block
    languagebash
    /opt/hydra/oracle/scripts/dump.sh -i hydra -p ais_netpassword -f hydra_dump export
    


  2. Очистка hydra2 hydra2:

    $ ./
    Code Block
    languagebash
    /opt/hydra/oracle/scripts/dump.sh -i hydra2 -p ais_net -s password drop
    


  3. Поднятие дампа на hydra2 hydra2:

    $ ./
    Code Block
    languagebash
    /opt/hydra/oracle/scripts/dump.sh -i hydra2 -p ais_netpassword -f hydra_dump import

    Во время импорта дампа в новую базу возможны ошибки следующего вида:

    Code Block
    languagetext
    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 следующий:

  1. Создать директории для конфигурационных файлов

    Code Block
    languagetext
    sudo mkdir /etc/hydra/hydra-utils


  2. Создать docker-compose.yml в новой директории:
    Для СУБД Oracle 11 необходимо использовать следующий docker-compose.yml:

    Code Block
    languagebash
    title/etc/hydra/hydra-utils/docker-compose.yml
    version: '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:

    Code Block
    languagebash
    title/etc/hydra/hydra-utils/docker-compose.yml
    version: '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. Например: 

    Code Block
    languagebash
    titleЗначение переменной TZ
    TZ="Asia/Krasnoyarsk"

    ORACLE_HOME - каталог с установленным Oracle. Задано в /etc/environment.

  3. После создания файлов конфигурации необходимо перейти в директорию и установить образ:

    Code Block
    languagebash
    titleУстановка образа контейнера
    cd /etc/hydra/hydra-utils/
    sudo docker-compose pull


Пример вызова скриптов из контейнера для переноса дампа БД с hydra на hydra2 (для Oracle 19 вместо hydra-utils нужно вызывать hydra-utils-19с)
):

  1. Снятие дампа с hydra:

    Code Block
    languagebash
    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
    


  2. Очистка hydra2:

    Code Block
    languagebash
    sudo docker-compose -f /etc/hydra/hydra-utils/docker-compose.yml run --rm hydra-utils dump.sh -i hydra2 -p password drop
    


  3. Поднятие дампа на hydra2:

    Code Block
    languagebash
    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


Warning
titleDDL

В ходе снятия дампа не должны выполняться DDL выражения, в том числе TRUNCATE и очистка очередей, иначе снятие дампа завершится с ошибкой ORA-01466: unable to read data - table definition has changed


Note
titleПримечание

Так как процедура снятия резервных копий с помощью утилиты expdp (скрипт dump.sh) является достаточно ресурсоемкой, снимать резервные копии БД рекомендуется в ночное время в часы наименьшей нагрузки на сервер (как правило, с 2-х до 4-х часов ночи).


Note
titleПримечание 2

При выполнении любого drop (даже отдельных схем) все открытые соединения с базой будут принудительно завершены


Note
titleПримечание 3

После выполнения поднятия дампа необходимо проверить лог импорта (файл с суффиксом _impdp.log в каталоге с дампом) на наличие ошибок


Note
titleПримечание 4

При копировании дампа на внешнее хранилище необходимо копировать и лог экспорта (файл с суффиксом _expdp.log в каталоге с дампом)


Note
titleПримечание 5

Новые профили пользователей, отличные DEFAULT, не сохранятся при снятии дампов. Это происходит только при экспорте полного бекапа со всей БД. Подробнее: Export and Import Modes

Полный список команд для получения DDL кастомных профилей можно получить при помощи следующего SQL запроса:

Code Block
languagesql
SELECT  DBMS_METADATA.GET_DDL('PROFILE',PROFILE)
FROM    DBA_USERS
WHERE   PROFILE != 'DEFAULT'
GROUP BY PROFILE;

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




Отменить процесс экспорта/импорта дампа можно с помощью CTRL-C и команды kill_job:

Code Block
...
. . 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

 

Действия после поднятия дампа

Note

Выполнять под пользователем БД AIS_NET

Контроль невалидных объектов

После поднятия дампа необходимо убедиться что в базе данных нет невалидных объектов.

Для этого необходимо выполнить скрипт компилляции

Code Block
languagesql
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;
/

И проверить наличие невалидных объектов

Code Block
languagesql
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_ — ядро приложения миграции (если данные объекты не используются).

Анализ БД

Перед началом использования БД необходимо выполнить полный анализ БД.

Для этого необходимо выполнить скрипт, приведенный ниже.

Следует учесть что анализ БД может занимать весьма продолжительное время, поэтому рекомендуется выполнять его напрямую на сервере из sqlplus с использованием оконного менеджера, например screen (это позволит скрипту доработать даже в случае неожиданного обрыва связи с компьютером администратора)

Code Block
languagesql
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;
/