专栏首页杨建荣的学习笔记海量数据迁移之分区并行抽取(r2笔记53天)

海量数据迁移之分区并行抽取(r2笔记53天)

在之前的章节中分享过一些数据迁移中并行抽取的细节,比如一个表T 很大,有500G的数据,如果开启并行抽取,默认数据库中并行的最大值为64,那么生成的dump文件最50多为64个,每个dump文件就是7.8G,还是不小,况且在做数据抽取的时候,资源被极大的消耗,如果资源消耗紧张,可能可用的并行资源还不到64个。那么dump文件可能比7G还要大得多。 如果换一步来说,我们尝试调高并行的参数,可以支持100个并行,那么每个dump文件也有5G,也没有太大的改善。 所以自己在斟酌后考虑使用分区加并行的思想来做大表的切分。 生产中500G的大表肯定是做了分区操作,而且分区数可能还比较多。我们就设定为100个吧。 分区表的数据基本都是分散在各个分区的,考虑数据的不均匀分布,那么每个分区的数据可能在5~10G吧。 参照这个思想,假设开启并行,比如200M为一个基准点来切分分区表,比如分区表的某个分区含有5G的数据,那么需要开启25个并行即可,文件就会被切分为200M的很多细粒度的dump文件。按照10G来算,最多也是50个并行,比默认提供的并行参数还要低一些。 按照这个思想,对比较大的分区表才做分区+并行,如果是普通表就需要最大程度的应用并行,如果分区表比较小,那就可以不用使用分区+并行了。 目前我设定的基准为1G,比如一个分区表T,大小在1.5G,那么可以考虑开启分区+并行,如果分区表的大小为500M,那么就可以不用考虑使用分区+并行了,因为在每个分区中的数据可能相对比较少。 今天写了如下的脚本来做做分区抽取的判断脚本,如果分区表的大小在1G以上,才抽取分区信息,否则和普通表一样对待。

tablst=`cat ../parfile/tablst|awk '{print "'\''" $1 "'\'',"}'` #for segment within 50M, will use parallel 1, and parallel will calculated with segment_bytes_size_MB/50M page=200 sqlplus -s $1 <<EOF set feedback off set head off set line 100 set pages 0 set long 10000 set termout off col segment_name for a40 col parallel format 9999 spool tab_parall_temp.lst select segment_name,nvl(partition_name,'x'),ceil(sum(bytes/1024/1024)/$page) parallel from user_segments where segment_name in ( select segment_name from user_segments where segment_name in (select table_name from user_tables where table_name in ($tablst'x') and table_name not in (select table_name from user_external_tables)) group by segment_name having sum(bytes/1024/1024)>=1000 )group by segment_name,nvl(partition_name,'x') union select segment_name,'x',ceil(sum(bytes/1024/1024)/$page) parallel from user_segments where segment_name in ( select segment_name from user_segments where segment_name in (select table_name from user_tables where table_name in ($tablst'x') and table_name not in (select table_name from user_external_tables)) group by segment_name having sum(bytes/1024/1024)<1000 ) group by segment_name,'x' ;

spool off; EOF sed '/^$/d' tab_parall_temp.lst |sort > ../parfile/tab_partition_parall.lst rm tab_parall_temp.lst

生成的参数文件内容如下,对于普通表和较小的分区表而言,就默认补充了一个字符‘x', 便于稍后的处理时统一管理 MEMO P9_A3000_E1 1 MEMO P9_A3000_E2 1 MEMO P9_A3000_E3 1 MEMO P9_A3000_E4 1 MEMO P9_A3000_E5 1 MEMO PMAXVALUE_AMAXVALUE_EMAXVALUE 1 SERVICE x 36 SUBSCRIBER_HISTORY x 11 SUBSCRIBER x 5 对于大表的分区+并行抽取,可以考虑如下的脚本。

#### source owner $1 #### tab_name $2 #### target owner $3 #### dump directory $4 #### partition_name $5

function check_conn { Num=`echo show user | $ORACLE_HOME/bin/sqlplus -s $1| grep -i 'USER ' | wc -l` if [ $Num -gt 0 ] then echo DB details is accessible from $2 schema ... else ## inst is inaccessible echo Instance: DB detailsIs Invalid Or UserName/PassWord Is Wrong echo '***********************************************' exit fi }

check_conn $1 source echo . check_conn $3 target echo .

source_owner=`echo "$1" |awk -F@ '{print $1}'|awk -F/ '{print $1}'|tr '[a-z]' '[A-Z]'` target_owner=`echo "$3" |awk -F@ '{print $1}'|awk -F/ '{print $1}'|tr '[a-z]' '[A-Z]'` tab_name=`echo "$2"|tr '[a-z]' '[A-Z]'` partition_name=$5 tablst=`cat ../parfile/tablst|awk '{print "'\''" $1 "'\'',"}'`

tmp_parallel=`grep -w $tab_name ../parfile/tab_partition_parall.lst|grep $partition_name| awk '{print $3}'` echo $tmp_parall tmp_dump_cnt=`ls -l ../DUMP/${tab_name}*.dmp|wc -l` tmp_dump_cnt=`expr $tmp_dump_cnt + 1 ` echo $tmp_dump_cnt tmp_parallel=`expr $tmp_parallel + $tmp_dump_cnt `

for i in {${tmp_dump_cnt}..${tmp_parallel}}; do echo \'${tab_name}_$i.dmp\', >> tmp_${tab_name}_par_dmp.lst done

sed -e '/^$/d' -e '$s/.$//' tmp_${tab_name}_par_dmp.lst > ../DUMP_LIST/${tab_name}_par_dmp.lst dump_list=`cat ../DUMP_LIST/${tab_name}_par_dmp.lst` #echo $dump_list #echo $tmp_parallel if [[ $partition_name = 'x' ]] then partition_name='' else partition_name='partition('$partition_name')' fi

sqlplus -s $3 <<EOF set feedback off set serveroutput on DECLARE datapump_flag number(2); begin select count(*) into datapump_flag from user_tab_privs where table_name=upper('$4') and grantee=upper('$target_owner') and privilege in ('READ','WRITE'); if(datapump_flag=2) then dbms_output.put_line( 'Directory '||'$4'||' has read,write permission ,proceed...'); else dbms_output.put_line( 'WARNING! Directory '||'$4'||' does not have read,write permission to $target_owner ,Please check again...'); return; end if; end; / EOF

echo .

sqlplus -s $1 <<EOF set feedback off set serveroutput on DECLARE TABLE_FLAG number(2); begin select count(*)into table_flag from all_synonyms where owner=upper('$source_owner') and table_name=upper('$2') ; if(table_flag>0) then dbms_output.put_line( 'SYNONYM '||'$tab_name'||' exists in CONNECT account,proceed...'); else dbms_output.put_line( 'SYNONYM does not exists in CONNECT account,please check again'); return; end if; end; / !echo .

DECLARE TABLE_FLAG number(2); begin execute immediate 'select count(*) from all_external_tables where owner=upper(''$target_owner'') and table_name=upper(''$2'')' into table_flag; if(table_flag>0) then dbms_output.put_line( 'External table exists in mig account,proceed...'); --execute immediate 'drop table $3.$2_ext'; end if; end; / exec dbms_output.put_line('Get Dump file for $source_owner.$2 $partition_name...');

conn $3 set timing on create table $target_owner.${tab_name}_ext ORGANIZATION EXTERNAL (TYPE ORACLE_DATAPUMP DEFAULT DIRECTORY $4 ACCESS PARAMETERS( nologfile) LOCATION ( $dump_list ) ) parallel $tmp_parallel as select /*+ parallel(t $tmp_parallel) */ * from $source_owner.$tab_name $partition_name t; set feedback off; set timing off drop table $target_owner.$2_ext; EOF echo . rm tmp_${tab_name}_par_dmp.lst exit

脚本生成的日志如下:

Get Dump file for APP_TMP.MEMO partition(P5_A2000_E2)... Elapsed: 00:00:00.52 DB details is accessible from source schema ... DB details is accessible from target schema ...

447 Directory new_test has read,write permission ,proceed... SYNONYM MEMO exists in CONNECT account,proceed...

Get Dump file for APP_TMP.MEMO partition(P5_A2000_E3)... Elapsed: 00:00:00.73 DB details is accessible from source schema ... DB details is accessible from target schema ...

449 Directory new_test has read,write permission ,proceed... SYNONYM MEMO exists in CONNECT account,proceed...

Get Dump file for APP_TMP.MEMO partition(P5_A2000_E4)...

生成的dump文件如下所示,可以看到生成了几百个相关的dump文件。 -rw-r----- 1 prodbuser dba 15826944 Aug 3 18:13 MEMO_460.dmp -rw-r----- 1 prodbuser dba 13254656 Aug 3 18:13 MEMO_461.dmp -rw-r----- 1 prodbuser dba 15044608 Aug 3 18:13 MEMO_462.dmp -rw-r----- 1 prodbuser dba 15015936 Aug 3 18:13 MEMO_463.dmp -rw-r----- 1 prodbuser dba 13135872 Aug 3 18:13 MEMO_464.dmp -rw-r----- 1 prodbuser dba 13266944 Aug 3 18:13 MEMO_465.dmp -rw-r----- 1 prodbuser dba 15003648 Aug 3 18:13 MEMO_466.dmp -rw-r----- 1 prodbuser dba 20480 Aug 3 18:13 MEMO_467.dmp -rw-r----- 1 prodbuser dba 20480 Aug 3 18:13 MEMO_468.dmp -rw-r----- 1 prodbuser dba 20480 Aug 3 18:13 MEMO_469.dmp

本文分享自微信公众号 - 杨建荣的学习笔记(jianrong-notes),作者:r2笔记53天

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2014-08-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • MySQL中需要重视的隐式转换

    在系统集成,对接的过程中,很多时候我们都会忽略数据类型的兼容性,导致在系统运转起来的时候,原本正常的流程会容易堵塞,其中一个潜在的原因就是因为数据隐式转换带来的...

    jeanron100
  • 通过Java程序测试数据库连接信息 (r10笔记第64天)

    很就没写Java了,今天简单问了下行情,如今都是Java 9的时代了,老系统基本上都是在Java 7。 Oracle中很早就糅合了Java,Oracle 10g...

    jeanron100
  • 关于数据库中的一些name(r3笔记第64天)

    如果接触数据库有些时间了,可能会碰到很多关于数据库相关的名字,比如ORACLE_SID,db_name,instance_name,db_unique_name...

    jeanron100
  • Struts2之Validation的简单使用实例

    本来不打算写这些细枝末节的东西了,因为在文档中都有现成的实例,写了也只能自己用来参考,不过这个Validation文档中给的不全,从网上查之后才知道用法。 首先...

    the5fire
  • python中的内置函数(双下划线) 原

    如果我们是直接执行某个.py文件的时候,该文件中那么”__name__ == '__main__'“是True,但是我们如果从另外一个.py文件通过import...

    晓歌
  • Crowd 批量添加用户(Postman 数据驱动)

    最近公司大量新员工入职,需要批量创建 Crowd 用户、设置密码、分配应用组等机械性重复工作(主要还是懒~),故把这个加餐任务分配给刚来的测试同学去研究。

    叨叨软件测试
  • RabbitMq的消息队列类型direct、fanout、topic、headers(headers抛弃)

    1 服务端 server 将 消息 msg_txt 投递 到 交换器 exchange_name 路由键为 routing_key_name ,当 有队列 qu...

    93年的老男孩
  • python通过配置文件共享全局变量

    在使用Python编写的应用的过程中,有时会遇到多个文件之间传递同一个全局变量的情况,此时通过配置文件定义全局变量是一个比较好的选择。

    十四君
  • Oracle通过substr,instr,translate函数的组合获取日期分割表

    写这一篇文章也是因为项目从SQL数据库导入Oracle数据库中遇到的问题,主要是我们要导入的数据有年月的分割表的查询。

    Vaccae
  • pyRedis - 操作指南:增/删/改/查、管道与发布订阅功能

    首先拉取 Redis 镜像, 这里我选择的是 redis:alpine 轻量级镜像版本:

    素质

扫码关注云+社区

领取腾讯云代金券