Экспорт - импорт БД oracle большого размера

Источник: surgutnet
Евгений Воронянский

Если вы читаете данную статью, то скорее всего Вас настигло несчастье. Экземпляр продуктивной БД доживает последние дни и вот вот перестанет вообще запускаться. Из RMAN-а вы восстановиться не можете, так как пользователи "наработали" достаточно большое количество данных, а архивные журналы с момента аварии безнадежно утеряны. Забегая вперед, отмечу, что с помощью ниже описываемого метода был произведен экпорт-импорт БД размером около 160GB за 18 часов. Платформа:

  1. Хост с "испорченным" экземпляром - RAM 8G, 4CPU, дисковый массив Clariion, SunOS Solaris, Oracle 8.1.7.4-64
  2. Хост приемник - RAM 24G, 12CPU, дисковый массив Clariion, SunOS Solaris, Oracle 8.1.7.4-64.

 Дополнительное программное обеспечение: ToadForOracle (Quest).

 Итак, приступим:

 Будем считать что для восстановления мы добавили отдельный диск для расположения на нем исполняемых файлов, а также журналов импорта/экспорта, и для того чтобы не путаться в достаточно большом количестве журналов выполнения создадим структуру дирректорий:

mount /dev/dsk/c1t1d0s0 /mnt/drive
 mkdir /mnt/drive/exp-imp
 chown oracle:dba /mnt/drive/exp-imp
 su - oracle
 cd /mnt/drive/exp-imp

 mkdir pipe ilog elog sql


 Внимание! В данной статье приводится вариант экспорта/импорта от владельца объекта. Т.е. прежде чем стартовать экспорт/импорт, необходимо убедиться что:

  1. В БД источнике все пользователи имеют право подключаться.ъ
  2. Нет заблокированных пользователей.

 В связи с пунктом 3 необходимо создать список заблокированных пользователе, а также сохранить хэши паролей пользователей.
 Для этого используем SQL приведенный ниже:

cd sql
 cat > lockuser.sql
Код:
#Список заблокированных пользователей
 whenever sqlerror exit sql.sqlcode;
set pause off;
set pages 0;
set linesize 140;
set feedback off;
set termout off;
 spool lockuser.spool.sql
select 'alter user "'//username//'" account lock;'
from dba_users
where account_status <> 'OPEN';
exit;

^D
 cat >user_password.sql
Код:
#Создание спаска хэшей паролей и
#скрипта подстановки времменного пароля для всех пользователей
 whenever sqlerror exit sql.sqlcode;
set pause off;
set pages 0;
set linesize 140;
set feedback off;
set termout off;
column cmd_line format a80
column tick format a3
column sum_bytes format 999,999,999,999
 spool return_pass.spool.sql;
select 'alter user "'//username//'" identified by values '''//password//''';' from dba_users;
 spool off;
 spool change_pass.spool.sql;
select 'alter user "'//username//'" identified by qqq;' from dba_users;
 spool off;
exit;
^4D
 cat > unlockuser.sql
Код:
#Разблокировка пользователей
 whenever sqlerror exit sql.sqlcode;
set pause off;
set pages 0;
set linesize 140;
set feedback off;
set termout off;
 spool unlockuser.spool.sql
select 'alter user "'//username//'" account unlock;'
from all_users
 /
 spool off;
exit;
^D

 Ниже приведен скрипт создания пользовательских схем (без данных) в БД приемнике. В нем необходимо исправить SID, домашнюю дирректорию Oracle, а также установить правильные языковые настройки и пароль не схему system, т.е "system/pass@source" и "system/pass@dest" должно являться строкой подключения.

cat > full_export_no_rows.sh
Код:
ORACLE_HOME=/u01/app/oracle/products/8.1.7.4; export ORACLE_HOME
 ORACLE_SID=ORCL; export ORACLE_SID
 EXP=$ORACLE_HOME/bin/exp
 IMP=$ORACLE_HOME/bin/imp
 NLS_LANG=AMERICAN_AMERICA.CL8MSWIN1251; export NLS_LANG
 DUMP_DIR=/mnt/drive/exp-imp
 PIPE=$DUMP_DIR/pipe/exp_full_pipe
 ELOG=$DUMP_DIR/elog/$ORACLE_SID-full-`date +%Y%m%d`.elog
 ILOG=$DUMP_DIR/ilog/$ORACLE_SID-full-`date +%Y%m%d`.ilog
 rm -f $PIPE
 mknod $PIPE p  # Make the pipe
 date >> $ELOG
 date >> $ILOG
$EXP system/pass@source FULL=Y ROWS=N CONSTRAINTS=N INDEXES=Y  TRIGGERS=N log=$ELOG file=$PIPE& #2>/dev/null 1>/dev/null &     # Export to the pipe
$IMP system/pass@dest FULL=Y IGNORE=Y  log=$ILOG file=$PIPE #Import from the pipe
 date >> $ELOG
 date >> $ILOG
 rm -f $PIPE
^D

 По аналогии создаем скрипт, с помощью которого можно перенести отдельный объект.

cd ..
 cat > table_export.sh
Код:
ORACLE_HOME=/u01/app/oracle/products/8.1.7.4; export ORACLE_HOME
 ORACLE_SID=ORCL; export ORACLE_SID
 EXP=$ORACLE_HOME/bin/exp
 IMP=$ORACLE_HOME/bin/imp
 NLS_LANG=AMERICAN_AMERICA.CL8MSWIN1251; export NLS_LANG
 DUMP_DIR=/mnt/drive/exp-imp
 PIPE=$DUMP_DIR/pipe/$1.$2
 ELOG=$DUMP_DIR/elog/$ORACLE_SID-$1.$2-`date +%Y%m%d`.elog
 ILOG=$DUMP_DIR/ilog/$ORACLE_SID-$1.$2-`date +%Y%m%d`.ilog
 rm -f $PIPE
 mknod $PIPE p    # Make the pipe
 date >> $ELOG
 date >> $ILOG
$EXP $1/temp_pass@source TABLES=$2  COMPRESS=Y FEEDBACK=1000 log=$ELOG file=$PIPE   2>/dev/null&     # Export to the pipe
$IMP $1/temp_pass@dest TABLES=$2 COMMIT=Y IGNORE=Y  log=$ILOG file=$PIPE 2>/dev/null # Import from the pipe
 date >> $ELOG
 date >> $ILOG
 rm -f $PIPE
^D

Для полного счастья строим отсортированный по размеру список таблиц, данные которых необходимо перенести с помощью следующего SQL:

cat >list_tbls.sql

Код:

whenever sqlerror exit sql.sqlcode;
set pause off;
set pages 0;
set linesize 150;
set feedback off;
set termout off;
column cmd_line format a80
column tick format a3
column sum_bytes format 999,999,999,999
 spool master.list;
--select '/mnt/drive/exp-imp/full_export_no_rows.sh' from dual;
select '/mnt/drive/exp-imp/table_export.sh '//owner//' '//segment_name cmd_line,' # ' tick,
sum(bytes) sum_bytes
from dba_segments
where segment_type = 'TABLE'
and owner <> 'SYS'
and owner not like 'AURORA%'
group by owner, segment_name
order by sum(bytes) desc;
 spool off;
exit;
^D
 

Далее создем скрипт который позволит пускать необходимые процессы в параллели:

cat >paresh

Код:

#!/bin/bash
#Исправте количество запускаемых процессов
#А также путь к командному файлу
 message()
{
   timestamp=`date +%Y.%m.%d:%H:%M`
   echo "$timestamp $*" / tee -a $logfile
   return
}
 get_shell()
{
   echo "`date` $1 Shell Request $$" >> $lklogfile
    while :  do
       next_shell=""
       if [ ! -s ${workfile} ] 
       then
       break
       fi     
       if [ ! -f $lockfile ]
       then.
       echo $$ > $lockfile
       echo "`date` $1 Lock Obtained $$" >> $lklogfile
       if [ "$$" = "`cat $lockfile`" ]
       then
           next_shell=`sed -e q $workfile`
           sed -e 1d $workfile > ${workfile}.tmp
           mv ${workfile}.tmp $workfile
           rm -f $lockfile
           echo "`date` $1 Shell Issued " >> $lklogfile
           return
       else       
       echo "`date` $1 Lock FAULTED $$" >> $lklogfile
       fi
       fi
       sleep 1
   done
   return
}
 paresh_slave()
{
   shell_count=0
   get_shell $1 
  
   while [ "$next_shell" != "" ]
   do 
       shell_count=`expr $shell_count + 1`
       message "Slave $1: Running Shell $next_shell"
       $next_shell 
       shell_status=$?
       if [ "$shell_status" -gt 0 ]
       then  
           message "Slave $1: ERROR IN Shell $next_shell 2status=$shell_status"
           echo "Slave $1: ERROR IN Shell $next_shell status=$shell_status" >> $errfile
       fi                       
       get_shell $1      
      done 
   message "Slave $1: Done (Executed $shell_count Shells)"
   return
}

 paresh_driver()
{
   rm -f $lklogfile
   if [ "$1" = "" ] 
   then                 
       master_file="/mnt/drive/exp-imp/master.list"
       echo $master_file
   else                         
   if [ ! -f "$1" ]       
   then                     
       echo "$0: Unable to find File $1"
       exit 1 
       else    
       master_file="$1" 
       fi
   fi
   if [ "$2" = "" ]         
   then                         
      parallel_count=24 #(CPU*2) 
   else                        
   if [ "$2" -lt 1 ]     
   then                    
   echo "$0: Parallel Process Count Must be > 0"
                              
   exit 1                  
   else                     
      parallel_count=$2
      fi
          fi
   message "------------------------------"
   message "Master Process ID: $PARESH"
   message "Processing File: $master_file"
   message "Parallel Count: $parallel_count"
   message "Log File: $logfile"
   message "------------------------------"
   cp $master_file $workfile    
   while test $parallel_count -gt 0
   do                          
   if [ ! -s $workfile ]
   then                       
   message "All Work Completed - Stopped Spawning at $parallel_count"
   break
   fi
   $0 $parallel_count &
   message "Spawned Slave $parallel_count [pid $!]"
   parallel_count=`expr $parallel_count - 1`
   done
   wait
   message "All Done"
   return
}

# main
if [ "$PARESH" != "" ];
  then
 workfile=/tmp/paresh.work.$PARESH
 lockfile=/tmp/paresh.lock.$PARESH
 lklogfile=/tmp/paresh.lklog.$PARESH
 ogfile=/tmp/paresh.log.$PARESH
 errfile=/tmp/paresh.err.$PARESH
 paresh_slave $*
else
 PARESH="$$"; export PARESH
 workfile=/tmp/paresh.work.$PARESH
 lockfile=/tmp/paresh.lock.$PARESH
 lklogfile=/tmp/paresh.lklog.$PARESH
 logfile=/tmp/paresh.log.$PARESH
 errfile=/tmp/paresh.err.$PARESH
 rm -f $errfile
 paresh_driver $*
 rm -f $workfile
 rm -f $lklogfile
if [ -f $errfile ]
then
 message "*************************************************"
 message "FINAL ERROR SUMMARY. Errors logged in $errfile"
cat $errfile / tee -a $logfile
 message "*************************************************"
exit 1
 fi
 fi
exit

^D

 После создания всех необходимых файлов, а также базы данных на целевом хосте со всеми необходимыми табличными пространствами ставим перед фактом руководство, и приступаем к использованию только что созданных файлов:

 Построение списков:

cd sql
 sqlplus system/pass@source @lockuser.sql
 sqlplus system/pass@source @user_password.sql
 sqlplus system/pass@source @unlockuser.sql
 cd ..
 sqlplus system/pass@source @list_tbls.sql
 cd sql
Изменение паролей пользователей и снятие блокировок с аккаунтов.
sqlplus system/pass@source @change_pass.spool.sql
 sqlplus system/pass@source @unlockuser.spool.sql

 Экспорт/импорт пользовательских схем без данных:

cd ..
 ./full_export_no_rows.sh

Далее внимательно проверяем все что в дирректории ilog, elog и только после окончания экспорта/импорта схем запускаем ./paresh  и анализируем лог-файлы процессов импорта/экспорта.

 По завершению всех процессов для определения "потерянных" объектов (constraints, index…) используем Toad for Oracle (DBA->Compare Schemas, DBA->Compare Databases), собираем статистику, а также выполняем скрипт для определения разницы в таблицах на уровне количества строк, для работоспособности которого необходимо связать БД линком MIGRATION.WORLD :

cd /mnt/drives/exp-imp/sql
 cat > rows_tables_diff.sql
Код:
whenever sqlerror exit sql.sqlcode;
set pause off;
set pages 0;
set linesize 150;
set feedback off;
set termout off;
column cmd_line format a80
column name format a3
column Diff format 999,999,999,999
 spool rows_tables_diff.spool.sql;
select 'whenever sqlerror exit sql.sqlcode;'//chr(10)//
         'set pause off;'//chr(10)//
         'set pages 0;'//chr(10)//
         'set linesize 150;'//chr(10)//
         'set feedback off;'//chr(10)//
         'set termout off;'//chr(10)//
         'column cmd_line format a80'//chr(10)//
         'column tick format a3'//chr(10)//
         'column sum_bytes format 999,999,999,999'//chr(10)//
         'spool rows_tables_diff.txt'
from dual;
select
 'select name, sum(Dest) - sum(Source) diff '//chr(10)//
 'from ( '//chr(10)//
         'select '''//table_name//''' name,count(1) Dest, 0 Source '//chr(10)//
         'from '//owner//'.'//table_name//'@MIGRATION.WORLD union '//chr(10)//
         'select '''//table_name//''' name,0 Dest, count(1) Source '//chr(10)//
         'from '// owner //'.'//table_name//' )'//chr(10)//
         'group by name;' Str
from all_tables
where owner not in ('SYSTEM','SYS')
and owner not like 'AURORA%'
select chr(10)//'exit;' //chr(10) from dual;
exit;
^D


 И в зависомости от того в какой из БД был создан линк выполняем rows_tables_diff.spool.sql. Результат сравнения наблюдаем в rows_tables_diff.txt.

Значительно ускорить экспорт/импорт позволяет установка параметра скрытого параметра oracle - _disable_logging в true на БД в которую производится импорт, но при запуске БД в эксплуатацию его необходимо установить в false.

 Удачи.


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