天天看点

海量数据迁移之外部表切分

在前几篇中讨论过海量数据的并行加载,基本思路就是针对每一个物理表都会有一个对应的外部表,在做数据迁移的时候,如果表有上百G的时候,一个物理表对应一个外部表性能上会没有任何提升。如果需要做数据插入的时候,对undo是极大的挑战,从某种程度上而言,性能应该要比datapump要差。这个时候可以考虑一个物理表对应多个外部表,比如一个表有100G。可以考虑生成100个external dump 文件,然后加载生成100个外部表,每个dump文件对应一个外部表,这样做数据的插入的时候就相对容易控制了。每一个外部表的数据加载到目标库之后,commit一次,就能及时的释放Undo资源,提高性能。

比如表T生成了两个dump文件(t_1.dmp,t_2.dmp),就可以考虑如下的方式来加载,黄色部分是对应的dump文件。

CREATE TABLE T_EXT_1

   (    id number,object_id number,object_name varchar2(30),object_type varchar2(30),clob_test clob   ) 

   ORGANIZATION EXTERNAL 

    ( TYPE ORACLE_DATAPUMP

      DEFAULT DIRECTORY "EXPDP_LOCATION"

      LOCATION

       ( 't_1.dmp'

       )

    );

CREATE TABLE T_EXT_2

       ( 't_2.dmp'

对应的脚本如下:

其中在DUMP目录下存放着生成的dump文件,根据动态匹配得到最终生成了几个dump文件,来决定创建几个对应的外部表。

target_owner=`echo "$2" |awk -F@ '{print $1}'|awk -F/ '{print $1}'|tr '[a-z]' '[A-Z]'`

source_owner=`echo "$1" |awk -F@ '{print $1}'|awk -F/ '{print $1}'|tr '[a-z]' '[A-Z]'`

tab_name=`echo "$3"|tr '[a-z]' '[A-Z]'`

owner_account=$5

tmp_parallel=`ls -l ../DUMP/${tab_name}_[0-9]*.dmp|wc -l`

echo  parallel :$tmp_parallel

for i in {1..$tmp_parallel};

do

echo \'${tab_name}_$i.dmp\' >> tmp_${tab_name}_par_dmp.lst

done

sed -e '/^$/d'  tmp_${tab_name}_par_dmp.lst > ../DUMP_LIST/${tab_name}_par_dmp.lst

rm tmp_${tab_name}_par_dmp.lst

dump_list=`cat ../DUMP_LIST/${tab_name}_par_dmp.lst`

print "

conn  $1

set feedback off

set linesize 100

col data_type format a30

set pages 0

set termout off

SELECT 

        t1.COLUMN_NAME,  

        t1.DATA_TYPE  

        || DECODE (  

             t1.DATA_TYPE,  

              'NUMBER', DECODE (  

                              '('  

                           || NVL (TO_CHAR (t1.DATA_PRECISION), '*')  

                           || ','  

                           || NVL (TO_CHAR (t1.DATA_SCALE), '*')  

                           || ')',  

                           '(*,*)', NULL,  

                           '(*,0)', '(38)',  

                           || ')'),  

              'FLOAT', '(' || t1.DATA_PRECISION || ')',  

              'DATE', NULL,  

              'TIMESTAMP(6)', NULL,  

              '(' || t1.DATA_LENGTH || ')')  ||','

           AS DATA_TYPE

           from all_tab_columns t1 where owner=upper('$owner_account') AND table_name=upper('$3' )

order by t1.column_id;

"|sqlplus -s /nolog > ${tab_name}.temp

sed -e '/^$/d' -e '$s/.$//' -e  's/CLOB(4000)/CLOB/g' -e  's/BLOB(4000)/BLOB/g' ${tab_name}.temp > ../DESC_LIST/${tab_name}.desc

rm ${tab_name}.temp

for i in {1..$tmp_parallel}

do 

echo loading table ${tab_name} as ${tab_name}_EXT_$i

sqlplus -s $2

set timing on

set echo on

CREATE TABLE  ${tab_name}_EXT_$i

   ( 

  `cat ../DESC_LIST/${tab_name}.desc `

   ) 

      DEFAULT DIRECTORY $4

      LOCATION(

  `sed -n "${i}p"  ../DUMP_LIST/${tab_name}_par_dmp.lst`

    ));

EOF

exit

生成的日志类似下面的格式:

 loading table T as T_EXT_1

Elapsed: 00:00:01.33

 loading table T as T_EXT_2

Elapsed: 00:00:01.30