去年年底做了不少系统的数据迁移大部分系统由于平台和版本的原因做的是逻辑迁移少部分做的是物理迁移有一些心得体会与大家分享
首先说说迁移流程在迁移之前写好方案特别是实施的方案步骤一定要写清楚然后进行完整的测试我们在迁移时有的系统测试了四五次通过测试来完善方案和流程
针对物理迁移也即通过RMAN备份来进行还原并应用归档的方式(这里不讨论通过dd方式进行的冷迁移)虽然注意的是要将数据库设为force logging的方式在用RMAN做全备之前一定要执行
否则可能会产生坏块
对于逻辑迁移在job_processes设置为>的数值之前注意job的下次执行时间和job所属用户比如job的定义在之前已经导入但是在迁移之时job已经运行过那么迁移完成之后job的下次时间还是原来的时间这样可能会重复运行另外job通过IMP导入后job所属用户会变成导入用户的名称显然job原来的用户就不能对JOB进行管理了可以通过下面的sql进行修改
在迁移之前应该禁止对系统进行结构上的修改和发布比如表结构索引存储过程包等
如果是用exp/imp导入的对象包括存储过程等应该检查对象是否与原生产库一致比如由于dblink的原因imp之后存储过程不能创建导致有部分存储过程丢失尽管这些存储过程可能没有被使用
下面是一些加快迁移速度的技巧
通过dblink使用append insert的方式同时利用并行这种方式比exp/imp更快
对于有LONG类型的列insertselect的方式显然是不行的可以通过exp/imp的方式但是这种方式速度非常慢其原因在于imp时一行一行地插入表有另外一种方式即sqlplus的copy命令下面是一个示例
不过sqlpus的copy命令不支持有timestamp和lob列类型的表如果有timestamp类型的表可以通过在exp时加上rowid的条件将一个表分成多个部分同时操作对于有lob类型的表也可以同样处理(因为insert …select方式下有lob类型列时也同样是一行一行地插入)注意在这种方式下就不能使用direct的方式exp/imp下面是exp导出时parfile示例
将表分成几部分同时操作不仅仅可以利用rowid也可以利用表上的列比如说表上有一个created_date的列并且保证是递增插入数据那么这种情况下也可以使用这个字段将表分成不同的范围同时进行导出和导入不过使用ROWID通常具有更高的效率
当然对于有lob列的表可以按上述方式拆成多个insert方式同时插入不需要exp/imp
·对于特别大的分区表虽然使用并行可以提高速度但是受限于单个进程(不能跨DB LINK进行并行事务只能并行查询也即insertselect只能是SELECT部分才能进行并行)的处理能力这种方式下速度仍然有限可以并行将数据插入多个中间表然后通过exchange partition without validation 的方式交换分区这种方式将会大大提高了速度
·有朋友可能会问为什么不并行直接插入分区表当然如果是非direct path(append)方式则是没问题的但是这种方式插入的性能较低而direct path的方式会在表上持有mode=(互斥)的TM锁不能多个会话同时插入(update: 在insert 时使用这样的语句insert into tablename partition (partname) select * from tablename where …更简单更有效率)
·迁移时将数据分成两部分一部分是历史表第二部分是动态变化的表在迁移之前先导入历史表并在历史表上建好索引这无疑会大大减少迁移时业务系统中断时间
·迁移之前考虑清理掉垃圾数据
·迁移时应保证表上没有任何索引约束(NOT NULL除外)和触发器数据导入完成后再建索引建索引时同样同时使用多个进程跑脚本索引创建无成后应去掉索引的PARALLEL属性
·在创建约束时应按先创建CHECK约束主键唯一键再创建外键约束的顺序约束状态为 ENABLE NOVALIDATE这将大大减少约束创建时间而在迁移完成后再考虑设回为ENABLE VALIDATE
·通过使用dbms_statsexport_schame_stats和dbms_statsimport_schame_stats导入原库上的统计信息而不用重新收集统计使用
朋友们可以看到以上均是针对i的实际上在g甚至g环境下也仍然很多借鑒意义当然这些技巧不仅仅用于完整的数据库迁移也可以应用到将个别表复制到其他数据库上
这里没有提到的是利用物化视图或高级复制触发器之类的技术因为这些技术毕竟要修改生产库对生产库的运行有比较大的影响因此只有在停机时间要求特别严格而在这个时间内又不能完成迁移时才应该考虑
从迁移的经验来说只有完善的流程完整的测试才可以保证成功这里只是列举了一些小技巧如果对整个迁移过程有兴趣可以针对这个话题再进行讨论