
这两年我参与评估和落地的 Oracle 迁移金仓KingbaseES项目一只手数不过来从一百多张表的管理系统到几千张表的业务核心都有。很多人以为这只是一次“换数据库”的动作真正做下来才发现数据迁移只是最外层里面裹着 SQL 语法、存储过程、应用层框架、运维体系、甚至商务采购模式的重建。这篇文章不打算复述官方文档就围绕我实际踩过的坑、改过的代码、跟团队吵过的排期把 Oracle 迁金仓这摊事拆开讲透。先说结论这不是一个“该不该迁”的问题而是一个“迁之前把账算明白、迁的时候把兼容性控住、迁完敢不敢秒回切”的问题。尤其当你面对的是核心账务系统或者高并发交易链路时一个没注意到的数据类型映射可能就让上线 night 变成返工两个月的导火索。1. 项目背景为什么非迁不可迁移到底在搬什么1.1 一次迁移到底在搬什么从 Oracle 迁到金仓基本的表层动作是把表结构和数据搬到新库但如果只做到这一步后面应用上线必然炸。一次完整的迁移实际包含三条线数据线表结构、数据、序列、约束、索引、存储过程、函数、包、触发器、视图、同义词等数据库对象。这里最容易漏的是序列和同义词尤其公共同义词被多个应用直接引用时漏掉一个启动就报ORA-00942或者金仓侧的relation does not exist。应用线JDBC 连接串、连接池、ORM 方言、SQL 语句、分页插件、主键生成策略、事务隔离级别、无赖的硬编码。很多系统里 SQL 直接写在 Java 代码里这种改造量经常比想象中大一个量级。运维线备份恢复策略、监控告警、高可用切换、慢 SQL 采集、客户端的习惯替换。以前 DBA 用 Oracle Enterprise Manager现在要换成金仓的管理平台以前开发用 PL/SQL Developer 连 Oracle现在要接 KStudio 或兼容工具这部分的习惯成本会持续发酵。很多人低估了第三层认为“数据库换完DBA 的事”就完了。实际上运维体系的切换比数据和代码更漫长因为它影响的是人不是机器。1.2 什么时候需要考虑换引擎结合我的项目经验触发这个评估通常集中在四类情况商务层面的成本压力Oracle 的 License 和服务费用按核量计算随着业务增长一个新节点就是一笔不小的预算。很多企业换金仓第一驱动因素其实是这是个“省钱的账”。维保与可控性需求商业数据库的原厂支持、续保流程、权限开放在部分项目中会遇到响应慢或约束多的情况换成国产库之后源码和机制更透明很多问题可以自己定位。架构整合多个 Oracle 实例年久失修正好借国产化替代这个契机做一次整体收敛把老旧的存储过程、冗余表清理掉。合规与项目立项需要这个原因在国企、金融类项目里很常见国产化替代作为立项背景但落到技术层面仍然要回到迁移质量和成本控制。了解动机之后才能真正安排后续的优先级如果只是成本驱动那要重点评估“迁完多久回本”如果是为了架构整合那要考虑“借这次迁移能不能顺便清理历史包袱”。2. 迁移前的存量盘点与方案选型2.1 对象清单把家底盘清楚再动手我接到过的每一个迁移项目第一周基本不碰任何迁移工具只干一件事摸家底。家底摸清楚了后续所有排期和风险点就有了依据。首要是用一条 SQL 把对象类型和数量拉出来SELECT object_type, COUNT(*) FROM all_objects WHERE owner APP GROUP BY object_type ORDER BY 2 DESC;然后再把所有表按数据量排序明确哪些是千万级大表、哪些几十万行、哪些只有几千行的配置表SELECT segment_name, BYTES / 1024 / 1024 AS size_mb FROM dba_segments WHERE owner APP ORDER BY 2 DESC;这两条 SQL 就能回答三个关键问题要搬多少张表、哪些表是迁移重点、哪些存储过程需要重点改造。通常我会把这些信息汇总成一张《迁移对象清单》包括对象名、类型、行数估计、是否有分区、是否被存储过程引用、是否被外部接口调用。这张清单会直接决定后面用工具自动迁还是手工写脚本迁也决定加班几周。这里有个经验点不要只看当前数据量还要看增长速度。曾经有个生产库当前只有不到 200GB但按月增 30GB 的比例涨结果迁移方案按当前量设计双写窗口和磁盘预留全部低估差点造成落库排队。预判增长比预判存量更重要。2.2 兼容模式怎么选金仓数据库和其他国产库一个很不一样的设计是建库时可以选择不同的兼容模板常见的有 Oracle 兼容模式、MySQL 兼容模式、PostgreSQL 兼容模式。这个选择在项目启动阶段就要定死后面再改代价极高。如果你们的存量业务是纯正的 Oracle 技术栈我的建议非常直白使用金仓的 Oracle 兼容模式而不是像有些人说的“金仓本来就是 PG 内核直接用 PG 模式就行”。Oracle 兼容模式会在语法层面对ROWNUM、DUAL、()外连接、NVL、SYSDATE等做适配能显著减少 SQL 改写量。不过要注意选择 Oracle 兼容模式不代表所有 Oracle 语法都能裸奔。我在项目里仍然见过PIVOT这类特性在金仓里需要改写也见过START WITH CONNECT BY这种递归查询在不同兼容模式下行为不一致。所以更稳妥的做法是建库阶段固定好兼容模式在测试环境里把核心 SQL 全量跑一遍提前暴露。实操上用金仓自带的图形化工具建库时会有类似“数据库模板”的选项需要明确选择 Oracle 模板字符集建议选 UTF8区域选zh_CN.UTF-8。命令方式建库也可以指定模板但图形界面更直观也避免模板参数写错。建完之后最好连上去执行一句SELECT version();确认内核版本并确认兼容模式参数生效再开始后续操作。2.3 数据迁移工具选型这步是很多团队纠结的地方。我直接给出一个基于场景的选型表工具适用场景优点缺点金仓自带迁移工具KDTS中小规模、对象类型复杂的整体搬迁能迁结构、过程、数据操作较简单大表并行度有限碰到自定义类型容易停DataX 或自研并行任务大表、高吞吐、需要断点续跑并行效率高可控性强方便做分片只解决数据不管结构需要配合结构迁移脚本Kettle / 定时 ETL有清洗转换需求、增量同步可视化易调整性能一般配置较繁琐手工脚本 SQL小表、配置表、特殊校验场景最可控排错容易人工成本高我的经验是混合式结构对象用金仓自带工具做一轮基线大表数据用 DataX 分片并行小配置表直接脚本导入。这样既控制了工作量又保证了大数据量的迁移效率。无论选哪个工具都需要先跑一轮“数据抽样比对”不要直接全量。先用一小部分表验证字符集、字段长度、空值行为确认工具输出的数据形态符合预期后再启动全量。3. 从 Oracle 到金仓核心差异与改造要点这是整个迁移技术含量最高的部分。金仓虽然兼容 Oracle但底层机制仍然是 PostgreSQL 那一套很多 Oracle 里“看起来很合理”的写法到了金仓就需要改。3.1 数据类型映射表数据类型映射是表结构迁移的基础。我常用的映射关系如下Oracle金仓KingbaseES备注VARCHAR2(n)VARCHAR(n) / VARCHAR(n CHAR)留意字节和字符的差异NVARCHAR2(n)NVARCHAR(n)与字符集相关NUMBERNUMERIC / DECIMAL无精度场景推荐 NUMERICNUMBER(10)INTEGER / NUMERIC(10,0)看业务是否超范围NUMBER(18,2)NUMERIC(18,2)金额字段常用DATETIMESTAMP金仓 DATE 只到天Oracle DATE 带秒TIMESTAMPTIMESTAMP行为基本一致CLOBTEXT / CLOB金仓 TEXT 使用更顺手BLOBBLOB / BYTEA看驱动程序支持RAW(n)BYTEA需要应用层注意 hex 格式ROWID无直接对应应用依赖 ROWID 的需改写VARCHAR2 空串VARCHAR 空串空串和 NULL 不再混为一谈这里有三个容易出问题的地方。第一个是NUMBER无精度迁移成NUMERIC后会带来较高的运算开销如果确认整表没有小数可以在迁移 DDL 里显式指定INTEGER。第二个是DATE类型。Oracle 的DATE包含时分秒而金仓的DATE只包含年月日如果原来的日期字段存储了时间并且应用依赖这个时间迁移后所有查询都必须改成TIMESTAMP否则会出现一堆“差 8 小时”“时间全没了”的诡异问题。第三个是VARCHAR2(n)的字节语义。Oracle 默认VARCHAR2(20)表示 20 字节而金仓默认按字符长度。中文环境下如果原来按字节存了 6 个汉字迁移到金仓的VARCHAR(20)之后能存 20 个汉字容量上是变大了一般不会出错但这会导致字符序和截断行为不同某些校验逻辑需要重新核对。如果之前 DDL 里明确写了VARCHAR2(20 BYTE)迁移后最好按字符数重新评估防止上下游直接取字段长度做校验时踩坑。3.2 分页、序列与常用函数差异分页是每个业务系统都绕不开的改造点。Oracle 最经典的分页写法是三层嵌套ROWNUMSELECT * FROM ( SELECT t.*, ROWNUM rn FROM (SELECT * FROM sys_user ORDER BY create_time DESC) t ) WHERE rn 10 AND rn 20;金仓 Oracle 兼容模式下支持ROWNUM但不要高兴太早。ROWNUM在 PG 内核里不是物理行号而是查询结果集追加的伪列一旦 SQL 里有复杂的排序、连接或过滤条件执行计划往往不够理想。我更建议直接改成LIMIT/OFFSETSELECT * FROM sys_user ORDER BY create_time DESC LIMIT 10 OFFSET 10;如果用的是 MyBatis 这类框架可以继续用分页插件但要把helperDialect配置成postgresql否则插件在识别金仓方言时可能走错分支。序列方面Oracle 的用法是seq_user.NEXTVAL金仓兼容模式下也能用但这只是语法层兼容。底层序列的缓存机制并不一样。高并发插入场景下如果序列的 CACHE 太小会产生比较明显的争用建议在迁移时按并发量评估CREATE SEQUENCE seq_user INCREMENT BY 1 START WITH 10000 CACHE 100;函数方面NVL、SYSDATE、TO_CHAR、TRUNC这些高频函数金仓基本都能识别但格式串细节有差异。例如TO_CHAR(sysdate, yyyy-mm-dd hh24:mi:ss)能跑通但是TO_CHAR对数字的格式化、对NULL的处理在不同模式下可能有细微差别。项目里出现过TO_CHAR(amount, FM999,990.00)在 Oracle 里正常输出到金仓后格式失效的案例。这类函数问题最好的排查方式是在迁移前写一个“SQL 函数兼容跑批脚本”把系统里用到的几十个函数各造一条能触发边界的 SQL批量执行比对结果。3.3 存储过程、包和触发器的改写思路存储过程是迁移中改造量最大、最不能依赖工具的部分。金仓本身支持 PL/SQL 风格的存储过程所以 Oracle 的CREATE OR REPLACE PROCEDURE ... IS ... BEGIN ... END;结构可以直接跑通一部分。但以下三类问题几乎必然遇到内置包不等同DBMS_OUTPUT、DBMS_LOB、DBMS_SQL、UTL_FILE这些包在金仓里有对应或部分对应实现但参数和行为有差异。例如DBMS_OUTPUT.PUT_LINE没问题但UTL_FILE.FOPEN的目录授权机制不一致导致原来能写的文件路径全部报错。自治事务Oracle 里PRAGMA AUTONOMOUS_TRANSACTION这种自治事务写法金仓不一定能直接识别。我的做法是拆成独立存储过程在调用方通过显式事务控制实现同样效果。隐式游标、异常编码SQL%ROWCOUNT、SQL%FOUND这些游标属性大部分兼容但某些场景下金仓返回的影响行数时机和 Oracle 不同。异常处理里WHEN OTHERS THEN能正常使用但具体异常码比如ORA-01403和NO_DATA_FOUND的映射关系需要逐一验证。最好的办法不是逐条手工比对而是先抽取全部存储过程源码在金仓测试库中批量编译把报错收集出来形成 break 清单。一次编译跑完改造清单基本就出来了。手工逐条改一定会漏批量编译可以快速收敛。触发器改造也建议采用同样的思路。触发器里如果直接写了SELECT seq.NEXTVAL FROM DUAL这类逻辑迁移后问题不大但如果是AFTER INSERT ... FOR EACH ROW里对:OLD / :NEW做复杂判断就要注意金仓对:NEW的使用时机和 Oracle 可能不同。批量编译加单测是我在这些系统上唯一信得过的验证方式。3.4 空字符串、大小写与隐式转换这类隐形坑这一节全是血泪换来的。空字符串和 NULL 的区分问题。Oracle 里会被当作NULL所以WHERE col 查不到数据插入实际存入的是NULL。金仓基于 PostgreSQL 内核空字符串就是空字符串和NULL完全不是一回事。如果原系统有大量“插入空串”和“按空串过滤”的逻辑迁移后WHERE 条件全变。改造时建议统一用NULLIF(col, )和IS NULL判断而不是直接改业务逻辑。标识符大小写问题。Oracle 默认把不带引号的表名、字段名转成大写存储。金仓则把不带引号的标识符转成小写。于是原来 Oracle 里执行SELECT * FROM Sys_User可能是能找到大写表SYS_USER的到了金仓却会报relation sys_user does not exist。如果迁移后没有把 DDL 统一成小写后面所有 SQL 都要小心双引号。我建议在结构迁移时就把表名、字段名全部统一为小写这是最干净的方案。隐式类型转换问题。Oracle 对类型转换非常宽松比如WHERE user_id 007字符串可以被隐式转成数字。金仓就比较严格这种写法经常会报operator does not exist: integer text。改造策略是在应用层把所有参数类型写清楚或者在 SQL 中显式做好转换不要依赖数据库的“宽容”。4. Spring Boot 接入金仓 V8 的实操配置4.1 驱动安装与数据源连接应用层的第一步是把 Oracle 驱动换成金仓驱动。金仓 V8 对应的 JDBC 驱动类是com.kingbase8.Driver连接串前缀是jdbc:kingbase8://默认端口是54321。由于这个驱动不在公网 Maven 中央仓库通常是向项目组拿到驱动 jar 后手动安装到本地 Maven 仓库mvn install:install-file \ -Dfilekingbase8-8.6.0.jar \ -DgroupIdcom.kingbase8 \ -DartifactIdkingbase8 \ -Dversion8.6.0 \ -Dpackagingjar然后在 pom 中引入dependency groupIdcom.kingbase8/groupId artifactIdkingbase8/artifactId version8.6.0/version /dependencySpring Boot 数据源配置spring: datasource: driver-class-name: com.kingbase8.Driver url: jdbc:kingbase8://127.0.0.1:54321/appdb username: system password: Kingbase_2025 hikari: maximum-pool-size: 20 minimum-idle: 5有几个注意点如果驱动 jar 版本与数据库版本不一致可能连接后某些函数异常尽量用金仓官方配套版本。密码包含特殊字符时YAML 里要加引号否则解析会出问题。连接池参数不能照抄 Oracle。金仓在 PG 内核上默认连接数和事务行为有一些差异首次接入先小连接数压测再逐步放大。4.2 MyBatis 和 Hibernate 的适配MyBatis 场景下大部分 XML 里只是普通SELECT/INSERT/UPDATE注意几个高频改造点ROWNUM分页改为LIMIT/OFFSETsysdate尽量改为CURRENT_TIMESTAMPNVL可保留但建议逐步统一为COALESCE动态 SQL 里的||字符串拼接金仓支持但如果拼接时涉及 NULL 可能结果不一致尽量用CONCAT或COALESCE包一层。Spring Boot 里如果配了 PageHelper需要指定方言pagehelper: helper-dialect: postgresql reasonable: false指定为postgresql是因为金仓内核就是 PGPageHelper 生成的分页 SQL 会以LIMIT方式执行这是我在多套环境里验证比较稳的组合。Hibernate / JPA 场景下理想情况是使用金仓提供的方言类。如果当前 Hibernate 版本没有内置金仓方言可以退而使用PostgreSQLDialect但要在实体类主键生成策略上格外注意避免自动映射成hibernate_sequence这类 PG 序列而引发重复主键。更稳妥的做法是显式指定主键生成策略比如使用ASSIGNED或者维护好金仓侧的序列映射。4.3 金仓读写分离配置实践“Spring Boot 集成金仓读写分离”是我最近被问得比较多的问题。金仓支持一套主备架构应用侧实现读写分离的原理和 MySQL 差不多用多个数据源加路由。首先在配置里定义写入库和查询库spring: datasource: write: driver-class-name: com.kingbase8.Driver url: jdbc:kingbase8://10.0.0.11:54321/appdb username: system password: Kingbase_2025 read: driver-class-name: com.kingbase8.Driver url: jdbc:kingbase8://10.0.0.12:54321/appdb username: readonly password: Read_2025然后在应用内通过AbstractRoutingDataSource根据当前线程上下文选择数据源。比较简单的实现是写操作强制走 write 数据源读操作默认走 read 数据源事务内根据Transactional(readOnly true)做路由预留一个开关读库故障时自动降级到写库。这种应用层读写分离方案本质上依赖的是金仓主备之间同步是否及时。主库刚提交落盘、备库还没追平的时候读请求会拿到旧数据。对于一致性要求高的查询比如订单详情、账号余额这种建议强制走写库只有报表、列表、统计类查询走读库。我遇到的另一个坑是备库如果配置成只读某些 JDBC 驱动的元数据查询也会失败应用启动时报cannot execute SELECT ... in a read-only transaction。最后把只读用户加上了相关视图的查询权限才解决。这一块在上线前一定要有专门回归。5. 数据迁移执行与一致性校验5.1 分批全量迁移如何设计数据量一旦过亿一次性INSERT INTO ... SELECT ...很容易让事务日志膨胀、锁冲突失控最终中断。我的习惯是把“大表分片、小表示例、分批提交”作为原则。具体步骤大致是先迁移结构对象包括表、序列、约束、索引骨架。对数据量超过 100 万行的表按主键或者时间字段切分每片控制在几十万行以内。每批数据提交后立刻记录断点位置方便失败续跑。全部数据迁完后重建索引、主键和外键约束再收集统计信息。有触发器的表在批量导入阶段可以考虑临时关闭触发器导入完成后再开启避免逐行触发带来的性能灾难。分片迁移的伪代码思路SELECT MIN(id), MAX(id) FROM big_table; -- 确定边界 -- 按每批 N 万行计算分片区间 for (start min_id; start max_id; start step) { INSERT INTO target_table SELECT ... FROM source_table WHERE id start AND id start step; }这里有个容易被忽略的细节分片键必须选唯一且稳定的字段不能选普通索引字段否则数据重复或漏数时很难排查。没有主键的超大表我会先补一个临时编号字段或者用ROW_NUMBER生成批次再分片。5.2 增量同步与业务双写全量迁移完成不代表可以立刻切换上线因为全量迁移期间Oracle 库里还在产生新数据。这里我需要看项目容忍度来选方案如果业务允许停写那么停写、迁全量、核对、切换最干净。大多数管理系统可以这么干。如果业务要求在线切换就需要双写或者增量同步。我实践中更倾向“应用层双写 切读开关”的方案在代码里加一个动态配置把写操作同时发给 Oracle 和金仓金仓这边先只读不承担流量等金仓数据追平并验证稳定后把读流量切过来最后关闭 Oracle 写路径。这个方案对应用改造成本略高但回退非常容易一旦金仓这边出现性能问题把开关拨回去就能恢复。如果不想改动应用代码也可以使用金仓的同步工具做增量同步或者基于业务侧的唯一业务键做补数据。比如订单表可以用订单号更新时间作为增量条件每 10 分钟跑一次增量脚本。不同项目适合不同方案核心判断是业务能不能容忍短暂旧数据。5.3 数据一致性验证清单迁移上线前的数据校验我一般分成四层第一层行数一致。逐表比对COUNT(*)SELECT source AS side, COUNT(*) AS cnt FROM source_orders; SELECT target AS side, COUNT(*) AS cnt FROM target_orders;第二层指标一致。对金额、数量字段做SUM和AVG对比重点核对有小数位的字段SELECT SUM(amount), COUNT(*), COUNT(DISTINCT order_no) FROM target_orders;第三层关键键值一致。COUNT(DISTINCT)和最大最小值比对SELECT COUNT(DISTINCT user_id), MAX(order_time), MIN(order_time) FROM target_orders;第四层随机抽样比对。每个大表抽 1000 条逐字段比对原文。这一步虽然繁琐但最能发现字符集、空串、精度这类工具不会提示的问题。我在项目里就是这样发现了一个 CLOB 字段迁移后被截断的隐患。当时行数、金额都完全一致但随机抽样时发现某一条详情内容缺失最后 20 个字符追查下去是工具对超长 CLOB 做了默认截断。如果没有抽样这个坑直到生产曝光才会被用户发现。6. 国产化替代背后的成本博弈6.1 显性成本License、硬件与维保大多数人拍板迁移第一眼看的是 Oracle 的授权成本。这里我用一个比较保守的估算模型来做对比。一个中型业务系统两节点 RAC每节点 16 核Oracle 商业授权加三年维保市场采购里通常是一个大几十万到百万级的盘子。如果业务扩容再加节点或核数费用还要继续往上走。金仓作为国产化数据库采购模式通常按节点或容量授权整体费用比 Oracle 低一个量级。这是显性成本里最直观的差异。但“epoch 迁移项目”的显性成本还包括新购置服务器或云资源、备份存储扩容、迁移工具采购、原厂驻场服务。这部分经常被低估尤其当旧库用了大量专用存储和高级功能时新环境不一定能完全对等替代。6.2 隐性成本人月、排期和试错显性成本好算隐性成本才是真正容易让预算翻车的部分。我见过多次项目预算只含 DBA 迁移工作量完全没算应用开发的改造量结果上线前发现一批 XML 里的 SQL 全部要改硬塞出三个月加班。实际上应用改造人月通常等于甚至超过数据库迁移人月。我习惯用一个粗估公式迁移总人月 ≈ 对象盘点脚本工作量 结构迁移工作量 数据全量迁移工作量 存储过程/函数改造工作量 应用 SQL 整改工作量 测试回归工作量举个真实例子一套 400 张表、120 个存储过程、30 个包的系统四名开发加一名 DBA评估下来用了 5 个人月做完技术适配额外 3 个人月做测试回归和数据校验。这个量级在常规系统里很典型算不上极端。隐性成本还包括团队学习和试错。第一次接触金仓的 DBA连默认的管理员账号、端口、备份工具都要重新熟悉第一次接触金仓驱动的开发也会遇到大小写和方言问题。这些试错不是一次性的迁移前会集中爆发迁完后还会零星出现。6.3 成本估算示例我习惯用一个五年 TCO 表格来跟项目组沟通成本项Oracle 原架构金仓迁移后商业授权与维保高且随核数增长低按节点/容量一次性迁移人力无中高应用改造是大头数据库维护工具成熟但工具授权也可能要钱平台化但生态待完善团队学习成本低初期高一年后趋稳扩容成本每加核心都贵相对可控回退风险成本无需要预留回退资源当然这不是说所有项目都该迁。如果系统复杂度极高、还在快速迭代期强行迁移会让业务节奏被拖垮反而得不偿失。我的建议是核心账务类系统先试点双跑外围系统先批量迁用一年时间把团队的踩坑成本消化在前端运营压力小的系统上。6.4 一套可落地的迁移切换策略成本博弈之后最终还要回到执行策略。我自己总结了一套相对稳妥的节奏先选一个小而完整的业务模块做“样板房”跑通全部流程建立团队信心。样板房验证通过后做全量对象盘点和代码扫描输出完整改造清单。外围系统先行分批迁移上线积累运维经验。核心系统最后迁上线前必须有双写期和回退预案。每次切换前做回退演练确保 Oracle 旧环境随时可切回。这套节奏的核心思想是不要寄希望于“一次切换完美成功”而是确保任何一次失败都不会影响业务连续性。7. 踩坑实录我见过的高频问题速查7.1 高频问题速查表现象可能原因处理办法启动报relation xxx does not exist标识符大小写不一致表名、字段名统一小写或者 SQL 里加双引号数据迁移后中文乱码字符集不一致建库时统一 UTF8连接串指定characterEncodingutf8分页结果重复或丢失ROWNUM和排序执行顺序不同改写为LIMIT/OFFSET存储过程编译报错内置包或语法不兼容批量编译梳理报错清单逐个改写ORA-01403或NO_DATA_FOUND异常异常映射不一致存储过程中检查游标和SELECT INTO行为金额精度不对NUMBER迁移成NUMERIC精度设置不当显式指定精度或整数类型批量插入极慢索引和触发器未关闭批量阶段禁用索引和触发器完成后重建应用连接超时驱动版本或连接池参数不匹配升级配套驱动调小连接池测试日期显示差 8 小时OracleDATE与金仓TIMESTAMP时区处理不同统一使用TIMESTAMP检查 JDBC 时区参数主键冲突序列从 1 开始迁移前把序列的START WITH调整到当前最大值之后7.2 两条小技巧第一条迁移前一定要做“空跑回归”。拿金仓测试库把生产上采集到的一批真实 SQL 全部执行一遍不需要真实数据量主要是验证语法和执行计划能不能出来。这个动作成本低、发现问题的效率极高。第二条所有存储过程、函数、包在迁移后改完先跑一轮“静态代码扫描”。我会写一个简单的脚本把代码里涉及的内置包名、系统函数全部拉出来跟金仓支持列表做关键词比对把存在不确定性的对象圈出来再逐个人工检查。这样比盲改快得多。7.3 我最后想分享的一点经验迁移项目做到后面拼的往往不是谁更懂 Oracle 或谁更懂金仓而是谁更懂自己的业务数据。我见过很多团队卡在语法兼容上最后发现真正的难点是历史 SQL 里那些“只有老人才知道为什么要这么写”的业务规则。所以在动手之前抽出时间找业务方把关键表、关键存储过程的逻辑捋一遍比多写一百个迁移脚本更有用。另外我做完几个项目后越来越倾向把国产化迁移当成一次“数据治理的契机”而不是纯粹的搬库。借这个机会把冗余表清理掉、把藏在应用里的 SQL 收敛到持久层、把主键生成策略统一掉迁移完成后的新系统反而比原来更好维护。这算是迁移之外的额外收益吧。