将一套稳定运行在Oracle上的业务系统迁移到DB2,并不是简单的导出导入数据。两套数据库在体系结构、数据类型、SQL方言以及事务控制上都有明显分歧,若仅依赖迁移工具自动转换,上线后极易出现功能异常或性能陡降。只有提前识别这些差异并制定对应策略,才能保障迁移后系统行为一致。

数据类型与对象结构的映射处理
Oracle和DB2在基础数据类型上名称不同但语义相近,直接一一对应往往埋下隐患。Oracle的NUMBER类型非常灵活,可以表达整数也可以表达小数;而DB2中需要根据实际精度选择DECIMAL(p,s)、INTEGER或DOUBLE。如果原表某字段定义为NUMBER(10),在DB2中应映射为INTEGER或BIGINT,若为NUMBER(12,2)则应使用DECIMAL(12,2)。忽略精度直接映射成DOUBLE可能导致金额类字段出现浮点误差。
除了字段类型,Oracle特有的对象也需要重构。比如Oracle用PACKAGE把一组存储过程和函数封装在一起,并可以定义包级变量维持会话状态;DB2没有包的概念,只能将包内每个过程独立创建为PROCEDURE或FUNCTION,包变量则需改为全局临时表或专用配置表。下表列出常见结构差异:
| Oracle对象 | DB2对应方案 | 注意点 |
|---|---|---|
| VARCHAR2 | VARCHAR | DB2的VARCHAR最大长度依页大小而定 |
| DATE含时分秒 | TIMESTAMP | Oracle的DATE实际存到秒,DB2 DATE只到日 |
| SEQUENCE | SEQUENCE | DB2序列语法类似但缓存参数需重设 |
| 同义词SYNONYM | 别名或视图 | DB2无完全等价物,可用视图模拟 |
在迁移表结构时,建议先通过DB2的db2look工具反向工程,再手工修正自动生成脚本中的类型偏差。对于字符集,Oracle常用AL32UTF8,DB2对应UTF-8编码数据库,建库时需显式指定,否则中文可能出现乱码或长度计算错误。
SQL语法与存储过程改造要点
Oracle的PL/SQL与DB2的SQL PL在控制语句上相似,但细节差别足以让自动转换后的过程无法编译。最典型的是游标循环:Oracle写FOR r IN (SELECT ...) LOOP,DB2中虽然支持FOR循环,但更常见的是用DECLARE CURSOR配合FETCH。另外Oracle的SYSDATE在DB2中要用CURRENT TIMESTAMP替代,DUAL表在DB2中可用SYSIBM.SYSDUMMY1或省略。
隐式类型转换是另一个重灾区。Oracle允许WHERE id = '123'这种字符串比数字,DB2通常报错或走不了索引。下面是一段有问题的Oracle风格代码以及DB2修正版:
-- Oracle风格,字符串直接比数字 SELECT * FROM orders WHERE order_id = '1001'; -- DB2修正,保持类型一致 SELECT * FROM orders WHERE order_id = 1001;
对于存储过程异常处理,Oracle用EXCEPTION WHEN OTHERS THEN,DB2使用DECLARE CONTINUE HANDLER FOR SQLEXCEPTION。迁移时要逐个过程检查错误捕获逻辑,否则原本能优雅回滚的事务在DB2里可能直接中断。此外,DB2对锁等待默认行为偏严格,若原Oracle应用依赖FOR UPDATE NOWAIT,在DB2里需调整为WITH RR USE AND KEEP EXCLUSIVE LOCKS之类写法。
触发器也是难点。Oracle行级触发器可引用:NEW和:OLD,DB2中用NEW_TABLE和OLD_TABLE过渡表,或者直接在触发器体内用NEW.前缀。下面展示DB2中一个简单触发器的正确结构:
CREATE TRIGGER trg_after_ins AFTER INSERT ON account REFERENCING NEW AS n FOR EACH ROW BEGIN INSERT INTO log_table(acc_id, create_at) VALUES(n.acc_id, CURRENT TIMESTAMP); END;
性能调优与迁移后验证策略
即便结构和语法都迁过去了,性能也可能天差地别。Oracle的基于成本的优化器与DB2的查询编译器对统计信息的依赖方式不同。迁移完成后必须对所有大表执行RUNSTATS收集分布统计,否则DB2优化器会选错访问路径。对于复杂报表SQL,应在DB2中用EXPLAIN工具查看实际执行计划,重点观察是否出现全表扫描。
索引策略也需重新审视。Oracle的函数索引在DB2中要用生成列加索引来模拟。比如原Oracle有CREATE INDEX idx_upper ON emp(UPPER(name)),DB2应先加生成列name_upper GENERATED ALWAYS AS (UPPER(name)),再建索引。另外DB2的缓冲池配置独立于表空间,需要根据内存大小分配BP1等缓冲池,避免默认过小导致物理读飙升。
最后要建立完整的迁移验证机制。除了行数比对,还应抽样校验数值精度、时间字段时区、空字符串与NULL的语义。Oracle中空字符串等于NULL,而DB2中空字符串是独立值,应用若依赖前者逻辑必须修改。建议编写自动化校验脚本,在灰度环境跑双写比对,确认DB2侧结果与Oracle一致后再切流量。