阿里巴巴数据库操作手册 19-数据迁移工具之sqlldr

V1.0

 

Revision

Author/Modifier Comments

No.

Date

1.0 2012/2/15 张中靖  
       

一、 目的

说明使用sqlldr进行数据迁移的前置条件、操作步骤,降低对对应用造成的影响及避免故障

二、 适用范围

l 所有线上库:数据迁移,数据初始化,以及应用几乎只读的表

三、 风险评估

使用sqlldr迁移数据时,普通方式加载数据本质是insert,对表的结构影响不大。使用需要rows控制事务大小。风险主要在使用direct方式加载上:

l 默认情况下会同时维护索引,如果设置参数SKIP_INDEX_MAINTENANCE=true,则不会维护索引。导致索引处于处于unusable状态。

l direct方式加载数据时,表上unique约束始终有效,unique约束的校验是在表加载数据完毕后rebuild索引时完成的,如果索引build时发现有违反unique约束的数据,会导致该索引处于unusable状态。

l direct方式加载数据时,索引结构相当于rebuild,对临时空间需求比较大。如果空间不足,会导致索引处于unusable状态。

l 如果数据空间不足导致加载报错,也会导致索引处于unusable状态。

l 如果启用savepoint机制,sqlldr进程被中断失败时,会使索引处于unusable状态。

l direct方式加载数据时会自动disable表上的触发器和约束(check、外键),在加载完成再次enable,由于enable时需要获得一个互斥的表锁,如果获得表锁失败,会导致无法成功enable。

l 表上的约束如果以enable novalidate方式启用时,direct方式加载数据时不会校验该约束,可能导致非法数据出现。

四、 操作流程

1. 准备工作

a) sqlldr不支持cluster表,及有global index的分区表。检查加载数据的目标表结构,尤其是触发器和约束,以及表上索引状态。如果有处于unusable的索引,需要评估是否rebuild生效,或者删除。

SELECT INDEX_NAME, STATUS FROM USER_INDEXES

WHERE TABLE_NAME = ‘tablename’ and status<>‘VALID’;

 

SELECT INDEX_NAME, PARTITION_NAME, STATUS

FROM USER_IND_PARTITIONS

WHERE STATUS <> ‘VALID’;

b) 如果有enable novalidate方式启用的约束,需要提前评估是否再对该约束enable validate一次。

select constraint_name, status, validated

from user_constraints

where table_name = upper(‘tablename’);

enable validate约束:该操作会锁表,需要在业务低峰期处理

alter tablename enable validate constraint constraint_name;

c) 估算表数据需要的空间和加载过程索引需要的临时空间大小。索引需要的临时空间计算方法:

1.3*(number_of_rows)*( 10 + sum_of_column_sizes + number_of_columns )

一般情况下是1.3倍,安全起见可以使用2倍系数【参考

d) 根据加载的文本文件内容编写controlfile,sqlldr命令使用的各个参数。SKIP_INDEX_MAINTENANCE 这个参数默认值是false,不建议修改。

e) 检查表上是否有活动事务

select *

from v$locked_object a, dba_object b

where a.object_id = b.object_id

and b.owner = ’schema’

and b.object_name = ’tablename’;

 

2. 执行过程

如果目标表是已存在数据,跟应用确认后,可以先进行exp导出备份,以防后面需

要回退。

这里给出一个示例,从算法提供的文本文件加载数据。

先根据需求编辑的control文件:’-‘后面是参数说明,实际使用时去掉

more ld_ws.ctl

load data

infile ‘totaldata_ae.txt’

append into table X_table_name

(

id sequence(200000000,1), –这里产生表id列的数据,自增长。2亿是起始值,1代表步长

GMT_CREATE   “sysdate”, –对gmt_create使用sysdate填充,下同

GMT_MODIFIED “sysdate”,

PRODUCT_ID POSITION(1) CHAR TERMINATED BY ‘\^’ “TO_NUMBER(:PRODUCT_ID)”, –这里开始读取正式数据,注意position(1),指定从文本各行的第一个字符开始。如果不指定product_id数据的起始位置,上面的gmt_create,gmt_modified列数据初始化会报错

group_ID TERMINATED BY ‘\^’,

FINGER_PRINT TERMINATED BY ‘\^’,

IMG_VERSION TERMINATED BY ‘\^’,

IMG_URL TERMINATED BY ‘\^’,

COMPANY_ID TERMINATED BY ‘\^’,

OFFLINE_DATE TERMINATED BY ‘\^’ “to_number(:OFFLINE_DATE)/3600/24+to_date(’1970-01-01 00:00:00′, ‘yyyy-mm-dd hh24:mi:ss’)”,–这里时间数字转成日期格式

grade TERMINATED BY ‘\t’ “TO_NUMBER(:grade)”

)

 

–加载数据

sqlldr userid=username/password@dbname direct=true control=ld_ws.ctl log=ld_ws.log bad=ld_ws.err

1

2

ld_ws.err保存不符合上面control文件格式的数据

 

3. 验证方案

a) 检查sqlldr的日志,确认是否报错,以及非法的数据。并在数据库上检查数据量和导入的数据量是否一致。

比如上面的数据迁移,检查数据量跟日志显示是否一致。

select count(*) from zzzzzz.x_table_name;

 

b) 检查是否有处于unusable状态的索引及索引分区,如果有,rebuild该索引。

SELECT INDEX_NAME, STATUS FROM USER_INDEXES

WHERE TABLE_NAME = ‘tablename’ and status<>‘VALID’;

 

SELECT INDEX_NAME, PARTITION_NAME, STATUS

FROM USER_IND_PARTITIONS

WHERE STATUS <> ‘VALID’;

c) 检查是否存在disable状态约束和触发器,如果存在手工enable

select trigger_name, status from user_triggers

where table_name = ‘tablename’

and status <> ‘ENABLED’;

 

select constraint_name, status from user_constraints

where table_name = ‘tablename’

and status <> ‘ENABLED’;

五、 核心对象风险

由于核心表访问、变更频繁,不宜直接使用sqlldr对核心表大量导入数据。需要先导入一个同构的中间表,再把数据分批insert到正式表。

六、 回退方案

sqlldr加载后可能数据有误,需要进行回退操作。

如果目标表本来就是空表,跟应用确认后,直接清空即可。

如果目标表原有数据,跟应用确认是否使用原有备份数据进行恢复。

七、 历史故障及教训

略。

  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓