上个月跟一位负责迁移项目的朋友聊天,他一开始信心满满,觉得Oracle数据库国产化替代嘛,数据导出来、导进去,应用改改连接串就能上线。结果到了业务回归阶段,一个每天夜里跑批的存储过程,在Oracle上只要两个小时,切到目标数据库上跑了整整一个晚上还没结束,最后定位到是里面一个递归查询的写法不兼容,走了全表扫描。他跟我说了一句话让我印象很深:"数据库国产化替代真正难的,从来不是数据搬不搬得过去,而是业务代码里那些用了十几年的Oracle习惯,搬不过去。"
这就是我写这篇文章的初衷。Oracle数据库国产化替代这个事,表面上是一次数据迁移,实际上是一场应用生态的"换血"。日常的增删改查大概率一次就能跑通,真正的隐形陷阱都藏在序列、触发器、存储过程、物化视图、分页写法、空字符串语义这些"平时没人注意,出了问题才要命"的细节里。这篇文章我会把迁移前、迁移中、迁移后最常见的核心痛点拆开讲,也会给出每个阶段的应对策略,给正在做或者准备做这个项目的团队一个可参考的路线。
1. 为什么Oracle迁移比想象中难:藏在日常功能里的兼容性深水区
1.1 基础SQL跑通了,业务SQL却翻了车
很多团队评估国产化替代时,第一反应是拿一段简单的SQL去目标数据库上执行,发现SELECT、INSERT、UPDATE、DELETE都没问题,就觉得兼容性不错。这个判断方式害了不少项目。真实业务里的SQL不是教科书里的SQL,它往往是三层嵌套子查询、动态拼接、带Oracle专有函数的组合体,平时写的时候没人想过"以后要换数据库"这回事。
举个例子,Oracle里对空字符串的处理是''等同于NULL,导致很多老系统的字段里混着两种"空值"。迁到目标数据库后,''变成了一个真实的空字符串,NULL还是NULL。如果目标库的UNIQUE约束、JOIN条件、WHERE判断逻辑和Oracle不一样,那么同样的SQL跑出来的结果集就可能不同。这种差异不会在单条SQL测试时暴露,但会在数据校验环节让你头疼很久。
还有ROWNUM分页。Oracle里经典的WHERE ROWNUM <= 20写法是在排序之前就截断行号的,很多老代码里还习惯先ROWNUM取数再ORDER BY,这在Oracle里"恰好能用",因为取出来的20条虽然不是全局有序的,但至少是稳定可复现的。换到目标数据库后,如果直接改写成LIMIT 20,配合ORDER BY的执行顺序不同,分页结果可能出现重复或漏数据。我见过一个报表系统迁移后,连续翻页时同一行数据出现在两页里,查了半天就是分页逻辑的语义差异。
所以,评估兼容性的第一步,不是拿测试用例去跑,而是拿真实业务SQL去跑。而且要把执行结果一条一条对比,不能只看"没报错"就认为通过。报错说明兼容性问题至少暴露了,最怕的是不报错、但结果跟Oracle不一致,这种"下毒式"差异排查成本非常高。
1.2 序列、触发器、系统包这些"老伙计"最容易被忽略
除了SQL语句本身,Oracle生态里还有一批高频使用的对象,它们在迁移评估时经常被忽略:序列(Sequence)、触发器(Trigger)、物化视图(Materialized View)、同义词(Synonym)、数据库链路(DBLink),以及一大票DBMS_开头的系统包。
先说序列。Oracle的逻辑是SEQ_NEXT_VAL和SEQ_CURRVAL,很多业务系统依赖它在应用层生成业务流水号。目标数据库如果自增列的语义和Oracle不同,迁移时就需要重新设计主键生成策略。这里有个典型的坑:直接沿用旧的序列值会导致主键冲突,把序列起点设太高又可能把号码段搞乱。我建议在迁移方案里把序列的INCREMENT BY、CACHE、NOCACHE参数先明确,凡是业务上把序列值当作"必须连续"的场景都要优先处理,因为国产数据库的序列实现各有差异,有的支持缓存,有的在高并发下会跳号。
再说触发器。Oracle的触发器语法支持得非常细,有BEFORE、AFTER、INSTEAD OF,还能配合REFERENCING NEW AS NEW之类的子句。目标数据库如果触发器能力不完整,就不能简单复制DDL,而是要评估这个触发器的逻辑能不能改写到应用层、存储过程或者改成约束。我之前遇到一个项目,迁移评估报告里写着"触发器数量131个,全部兼容",结果切到目标库后触发器编译失败了一半,原因是触发器体里用了DBMS_OUTPUT.PUT_LINE,这个包在目标库上根本不存在。这类系统包依赖是最恶心的:DBMS_SQL、DBMS_LOB、DBMS_LOCK、DBMS_ALERT,在Oracle里用得很顺手,但目标库不一定原生支持,每个都要单独替代方案。
1.3 性能兼容才是隐性风险的重灾区
前两节讲的是"能不能跑通",这一节讲"跑得动跑不动"。很多迁移项目在功能测试阶段一片绿,一到压测就原形毕露。原因很简单:Oracle的执行计划生成逻辑、优化器规则、索引实现和国产数据库差异很大,同样的SQL在Oracle上走索引,在目标库上可能被优化器判定为全表扫描更快。
我遇到过最典型的一个案例是分页查询。业务代码里有个ORDER BY多个字段的分页SQL,Oracle上通过组合索引轻松走INDEX RANGE SCAN,换到目标库后,同样的索引结构,优化器却选择了SORT ORDER BY加全表扫描,因为目标库对VARCHAR2字段的排序规则处理依赖字符集配置,统计信息又有偏差。最后不是改写SQL,而是重建了统计信息并调整了连接参数才解决。
这里想给一个经过多次验证的判断逻辑:性能兼容性评估一定不能只靠单条SQL看执行计划,必须做压测,并且压测的SQL要来自真实业务流量,不是自己编几条"代表场景"。很多团队到后期才发现性能不达标,就是因为评估阶段没用真实SQL,也没有做并发场景测试。性能问题的爆发往往不是单点慢,而是并发上来后目标库的资源调度、锁机制跟Oracle不一样,导致整体雪崩。
2. 迁移前先摸家底:对象盘点和SQL特征分析不能省
2.1 用数据字典导出完整的对象清单,别只信迁移工具的报告
很多迁移评估工具能自动扫描Oracle上的对象,并给出兼容性报告,这确实省事。但我见过不止一次:工具的扫描结果跟真实环境有出入,要么漏了某个Schema下的同义词,要么没识别出嵌套在存储过程里的动态SQL。所以我始终建议,工具报告只作为参考,必须以数据字典实际查询的结果为准。
做法上,可以连到Oracle实例,把DBA_OBJECTS、DBA_TABLES、DBA_INDEXES、DBA_SEQUENCES、DBA_TRIGGERS、DBA_SOURCE这些视图全部查一遍,按对象类型、所属Schema、最后DDL时间维度汇总。重点不是看总数,而是建立一份"对象与风险等级"的对照表,比如下表这样:
| 对象类型 | 数量 | 兼容性风险 | 备注 |
|---|---|---|---|
| 表 | 1200 | 中 | 需逐表核对字段类型、约束 |
| 索引 | 2600 | 中 | 关注函数索引、位图索引 |
| 同义词 | 180 | 高 | 目标库的同义词机制可能不同 |
| 触发器 | 131 | 高 | 大量依赖系统包,需逐个替换 |
| 存储过程/函数/包 | 340 | 高 | 包内动态SQL无法自动转换 |
| 物化视图 | 45 | 高 | 刷新机制差异大 |
| 序列 | 230 | 中 | 主键生成策略需重新设计 |
| Job(调度任务) | 60 | 高 | 调度能力差异明显 |
这份清单是后续所有评估和改造工作的基础,没有它,后面一切都是空中楼阁。清单里高风险对象要标注"必须人工介入"。
2.2 从源码和日志里抓取真实SQL,建立风险SQL清单
对象清单清楚了,下一步是搞清楚业务到底在跑什么SQL。有两类SQL要抓:一类存在存储过程、函数、包等数据库对象里,可以从DBA_SOURCE里提取出来人工审阅;另一类由应用直接发起,可以从应用侧的慢日志、数据库的监听日志、AWR快照存储的TOP SQL等渠道拿到,如果应用用了prepared statement,还能从数据库的V$SQL或DBA_HIST_SQLTEXT列出来。
我建议把所有SQL做一次特征分类,重点盯这几类高风险写法:
- 用了
ROWNUM、CONNECT BY、START WITH、MINUS、(+)这种Oracle专有语法的。 - 用了
NVL、SYSDATE、DECODE、TO_DATE格式化规则等的,虽然目标库一般有替代函数,但语义细节可能不同。 - 字符串拼接方式是
||还是CONCAT,空字符串和NULL混用的。 - 在存储过程里用
EXECUTE IMMEDIATE动态拼接的,这是静态扫描最难覆盖的部分。 - 默认值用
SYSDATE、USER、序列的字段。
把抓出来的SQL按"业务重要程度 × 兼容风险"两个维度做成矩阵,优先处理那些既重要又危险的SQL。不要想着全部自动驾驶式转换,工具能解决常见的80%,剩下20%要靠人工改写,这20%才是项目成败的关键。
2.3 搭建一个平行影子库,用小成本提前试错
很多团队上来就规划大迁移,忽略了"先做一轮试迁移"的价值。我做的每一个迁移项目,都会在目标数据库环境中按比例抽取一套"核心业务对象集",包含最复杂的几个存储过程、涉及最多表连接的报表SQL、以及所有触发器,然后投入真实代码跑一轮回归测试。
这个影子库不追求数据量完整,但结构一定要真:字段类型、索引、约束、默认值、字符集都要跟目标环境一致。用影子库验证的目的有两个:一是确认评估清单里的风险项是否真的会发生,二是给开发团队一个练手环境,让他们在正式迁移前先积累一批常见的改写案例。很多团队的迁移速度慢,其实不是因为难度大,而是因为第一次接触目标数据库的语法和特性,连报错信息都看不懂。影子库能把这段学习曲线提前吃掉大半。
3. SQL改写与对象重构:把硬骨头一块一块啃下来
3.1 高频Oracle语法怎么改:分页、递归、连接、函数
到了改造阶段,就会正式面对那些Oracle独有写法的替代方案。我整理了一份比较常见的对照思路,适合作为团队的起点,但实际改造时要结合目标库的具体语法能力来调整:
| Oracle写法 | 常见替代思路 | 注意事项 |
|---|---|---|
WHERE ROWNUM <= N | 使用LIMIT N OFFSET M或窗口函数 | 必须连同ORDER BY一起审核,否则分页结果顺序可能变化 |
START WITH ... CONNECT BY | 递归CTE(WITH RECURSIVE) | Oracle中循环遍历的顺序是深度优先还是广度优先,目标库不一定一致 |
WHERE column = 1(+) | LEFT JOIN/RIGHT JOIN显式写法 | 老代码里(+)放错位置会导致连接结果不对,改写时要逐条验证结果集 |
NVL(expr, val) | 类似语义的COALESCE | 注意NVL只判断NULL,COALESCE不支持嵌套类型不一致 |
SYSDATE | CURRENT_TIMESTAMP或目标库对应函数 | 要关注时区设置,SYSDATE返回的是数据库服务器本地时间 |
TO_DATE('2024-01-01','YYYY-MM-DD') | 目标库对应的日期转换函数 | 必须处理格式掩码差异,否则月份和日期可能反转 |
DUAL | 目标库一般也支持,但不强制 | 有些SQL不需要FROM DUAL,改写时顺手优化 |
MINUS | 对应集合运算关键字 | 注意空值与重复行处理逻辑可能不同 |
DECODE(expr, v1, r1, v2, r2, default) | CASE WHEN表达式 | 语义上最稳的就是改写为CASE表达式 |
这里边,最容易踩雷的是递归查询。Oracle的CONNECT BY写起来很短,循环逻辑藏在PRIOR关键字里,目标库的递归CTE通常要显式写出锚点成员和递归成员,改写的难点不是语法,而是递归顺序。比如组织架构树,Oracle默认的遍历顺序和递归CTE的顺序可能不同,导致树的父子层级展示顺序变了。某个报表里展示层级目录的顺序就是错的,最后在CTE里加了一个LEVEL字段用于排序,才把问题解决。
3.2 存储过程和PL/SQL包的重构策略
PL/SQL的改造是迁移中最耗时的部分,没有捷径。Oracle里的包结构(PACKAGE+PACKAGE BODY)在目标数据库里可能没有完全对等的概念,需要拆成普通存储过程、函数,或者重组为独立的模式对象。实践中最稳妥的做法是:
- 先把包体内每个子程序列出来,确认哪些是内部私有函数、哪些被外部调用。
- 按依赖关系拆成独立的存储过程或函数,保持原包头的调用签名不变,减少应用层改动。
- 逐个处理包里的游标、异常块、动态SQL和各种系统包调用。
这里有个非常容易忽略的点:Oracle的游标属性%FOUND、%NOTFOUND、%ROWCOUNT在存储过程里使用频繁,目标库不一定支持同样的写法。还有PL/SQL的批处理语法BULK COLLECT和FORALL,如果目标库不支持类似机制,碰到大批量数据处理的逻辑就必须改写为循环加分批提交,否则内存压力会很大。
另外,存储过程的异常处理也要重点检查。Oracle的WHEN OTHERS THEN后面往往会写一个ROLLBACK或者记录日志的操作。目标库的异常体系不一定完全一致,有些异常类型名不同,甚至OTHERS捕获的范围不一样。我建议在改造完成后,为每一个高风险存储过程单独准备一套测试数据,用白盒思路跑一遍分支,确保每个EXCEPTION分支在目标库上都能走到预期路径。
3.3 索引和统计信息:跟不上执行计划变化就谈不上性能
SQL改写完了、存储过程编译通过了,还不能高兴太早,因为目标库上执行计划可能完全不同。Oracle里常见几种索引结构,比如位图索引、函数索引、反转键索引,并不是所有目标数据库都原生支持。如果业务里有位图索引,目标库不支持,就得评估改写为普通索引还是要换业务查询方式。
迁移时一个常见的错误做法是:用Oracle的DDL生成脚本直接导入目标库,认为"索引一样就行"。实际上,索引的定义是跟着优化器走的。举个例子,Oracle里VARCHAR2(100)的字段默认不区分大小写,排序走的是二进制还是语言排序,跟数据库的NLS_SORT参数有关;目标库如果默认是二进制排序规则,同样的WHERE name = 'ABC'可能匹配不到存储为abc的数据。这种问题在开发环境根本发现不了,因为测试数据太规整了,只有到了真实数据校验的时候才会暴露。
我强烈建议在数据迁移完成后,专门做一轮"统计信息收集与执行计划比对"。不要求逐条SQL都跟Oracle一样快,但要找出那些"原来走索引、现在全表扫描"的高频SQL,优先干预。干预手段包括:重建统计信息、调整连接条件写法、创建新的函数索引、修改驱动表顺序、必要时在SQL里加优化器提示(前提是目标库支持)。这项工作是迁移后期最容易拖工期的地方,也是最能体现DBA经验的地方。
4. 数据迁移:从全量导出到增量追平,一致性怎么保障
4.1 全量迁移工具与方式怎么选
数据迁移的技术栈很多,有基于逻辑导出的迁移工具,也有基于数据同步的中转工具。选择哪种,取决于停机窗口、数据量、网络带宽和一致性要求。常见的两种思路对比:
| 方式 | 适用场景 | 优势 | 风险 |
|---|---|---|---|
| 逻辑导出导入 | 小中型数据量,可接受较长停机窗口 | 结构可控,便于校验和调整 | 大量数据处理慢,大表回灌时间较长 |
| 全量迁移 + 增量追平 | 大数据量、停机窗口短 | 增长式同步,切换时只需处理少量增量 | 增量同步链路配置复杂,事务一致性要求高 |
我一般建议优先考虑"全量迁移+增量追平",核心原因是停机窗口几乎不可能无限长。所谓增量追平,就是先用全量工具把历史数据搬完,然后通过日志或时间戳把持续产生的业务增量同步到目标库,等到切换时刻,只需要停掉业务、追平最后几分钟的增量、验证一致,然后正式切换。这个方案的难点不在全量部分,而在增量链路的稳定性,尤其是数据库日志解析,对某些国产数据库来说,日志解析能力可能不如Oracle生态那么成熟,实际执行时要多预留时间。
4.2 大表的迁移顺序和速度控制
大表迁移是最耗时也最容易出幺蛾子的环节。我的经验是,先建结构,再关约束,再导数据,最后重建索引。顺序错了,后面会很被动。
第一步,只把表结构建到目标库,索引、约束、触发器等全部先不建。第二步,把外键约束、非空约束、唯一约束暂时禁用或延后,因为导入数据过程中如果每插入一行都要检查一次约束,速度会被拖垮。第三步,按主键范围拆分成多个批次,每个批次控制在10万到50万行之间,分批提交事务。为什么拆批次?因为单条大批量事务如果中途失败回滚,代价非常大;批次小了还能做断点续传,哪批失败就重跑哪批。
关于并行度,我想特别提一句:不是并行度越高越好。目标数据库在数据导入期间会产生大量重做日志和索引维护开销,盲目开几十个并行任务,很可能把目标库的I/O和CPU直接打满,反而拖慢整体进度,甚至影响同期在跑的增量同步任务。我通常会把并行度压到目标库CPU核数的一半以下,先跑一个批次测耗时,再决定是否上调。稳妥永远比极限速度重要。
4.3 数据校验:行数一致只能算第一步
数据搬完了,怎么证明搬对了?很多团队的做法是"对比源和目标的总行数,一致就是成功",这个标准太松了。行数一致不代表数据内容一致,更不代表业务逻辑一致,中间可能有大量"看起来差不多但实际对不上"的数据。
我建议做四层校验:
- 表级行数对比:这是最基础的一层,用于快速发现明显的漏迁或重复迁入。
- 抽样字段级对比:对每张表抽一定比例的记录,逐字段对比值,重点关注字符类型、精度、日期格式、空值。
- 聚合值对比:对关键业务表做
SUM、COUNT、MIN、MAX等聚合对比,可以快速发现数值类偏差。 - 业务场景回归:拿几条真实业务链路跑一遍,比如下单、审核、出库、对账,确保核心流程走通。
这里有个实战教训:Oracle里的NUMBER(10,2)字段迁移到目标库后,如果目标库没有完全等价的数值类型,可能被映射成NUMERIC(10,2)或DECIMAL,表面看没问题,但空值变成0、精度被截断的情况时有发生。所以数据校验一定要抽查真实业务数据,特别是那些有默认值、有触发器填充、历史数据不规范的字段。
在增量追平阶段,还要确定"同步截止时间点"。目标库追平到哪一秒钟,意味着从那一秒开始,业务就可以切到新库了。这里必须保证增量同步的事务顺序不乱,否则可能出现父表记录还没到、子表记录先到了的尴尬情况。上线前务必做一次完整的增量演练,至少要演练到"切换后业务正常"。
5. 应用改造与业务验证:从双跑验证到灰度切换的完整节奏
5.1 连接层改造:不只是改个连接字符串
数据库换了,应用侧的连接方式也要跟着变。这块的改造工作量看起来不大,但细节密集。首先是驱动替换,Oracle的JDBC驱动换成目标数据库的驱动后,连接池参数需要重新评估,比如maxActive、maxWait、validationQuery这些参数在目标库上表现可能不同。
其次是连接字符串本身。很多老应用把数据库地址、用户名、密码、连接参数硬编码在配置文件中,迁移时容易漏改。我见过一个系统,连接池配了三个数据库地址,只改了第一个,上线后一部分连接还在连Oracle,导致数据"两边都写了一份"。正确的做法是在迁移前整理一份"数据源清单",列出所有配置文件、环境变量、JNDI数据源地址,统一替换后做一次全局扫描。
还要特别关注SQL方言配置。很多ORM框架默认会对Oracle方言做特殊处理,比如分页语句自动生成ROWNUM版本,或者使用SEQ.nextval获取主键。目标库的方言配置如果不对,ORM不但不会生成正确的SQL,反而可能把应用层的语法错误吞掉,到线上才爆发。切库之前,建议把ORM的方言配置、主键生成策略、分页插件逐项核对。
5.2 双跑验证:不是简单把流量跑两遍
应用改造完成后,最稳妥的验证策略是"双跑",也就是让业务流量同时经过旧库和新库,比较两边的结果。但双跑不是简单地部署两套环境、两边各跑各的,那样根本没法发现差异。
有几种可落地的做法:
- 读流量双跑:把查询类流量分出一部分到新库,业务读写仍然走Oracle,通过比对查询结果来验证SQL改写正确性。这个方式对只读报表类系统非常有效。
- 影子表对比:在Oracle环境里建一套目标库的映射结构,应用写入时同时写两边,然后定时对比数据差异。
- 消息或日志回放:把真实业务请求记录成日志,离线回放到新库,人工比对结果。
双跑期间最需要盯的是性能指标:新库的平均响应时间、慢SQL数量、错误率、数据库连接数。如果双跑阶段就一直出现性能拐点,不要强行上线,回头查执行计划和资源争用。我见过最成功的双跑策略是:应用层加了一个DAO路由开关,可以按用户ID、按业务类型、按比例随时切换读写流量到新库,这等于给整个迁移加了一个"空中刹车",任何时候发现问题都可以秒级回切。
5.3 灰度切换和回退预案:上线不是终点
正式切换不建议一把梭,应当按业务模块、用户范围做灰度。比如先把非核心的报表查询切到新库,跑一个完整工作日,再切一部分交易流量,再逐步放大比例。切换顺序可以按"风险从低到高"来排,查询类→分析类→批处理类→核心联机交易。每个灰度阶段都要设一个观察期,至少覆盖一个完整的业务高峰时段。
回退预案这个事,很多团队说是"有",但其实只是一句话"不行就切回Oracle"。真到了要回退的时候,如果没有演练过,回退过程本身就是灾难。回退预案至少要包含几个要素:回退触发条件(如错误率超过X%、核心交易卡顿超过Y分钟)、回退操作步骤(含数据库连接切换、增量数据回补、DNS/负载均衡改动)、回退验证标准。这里有一个细节经验:切换完成后,Oracle环境至少要保留一到两周,期间持续开启增量同步反向追平。一旦决定回退,先把反向增量补回Oracle,再切流量,这样业务数据才不会丢。
6. 项目推进策略:风险、资源与节奏控制
6.1 团队技能转型:DBA和开发都得从"Oracle思维"里走出来
人往往是迁移项目里最大的变数。Oracle的DBA接触国产数据库后,第一反应通常是用Oracle的运维习惯去操作新库,比如用ALTER SYSTEM KILL SESSION的方式处理会话,但目标库的命令可能完全不同;连备份恢复、监控告警、参数调优这些日常运维动作都要重新学。开发团队更明显,写了十年ROWNUM分页、SYSDATE,改写成新语法时很容易下意识保留旧习惯,造成SQL语义偏差。
我的建议是,在项目启动的第一时间就做两件事:一是安排所有DBA和核心开发人员参加目标数据库的专项培训,二是建立团队内部的FAQ文档,把遇到过的兼容性报错、改写案例、性能问题持续沉淀下来。这个文档的复用价值非常高,后面几批迁移直接就查它,能省掉大量重复试错。
6.2 排期设计:别指望两三个月跑完大迁移
Oracle数据库国产化替代的排期经常被低估。我见过一个项目,计划两个月完成全部迁移,实际做到第六个月还在处理存储过程改写,原因就是前期评估阶段没有把PL/SQL的改造量估算进去。以我个人的经验,一个中等复杂度的系统(假设有几百个存储过程、几十张核心大表、报表查询密集),合理的时间分布大致是:
| 阶段 | 时间占比 | 关键交付物 |
|---|---|---|
| 评估与对象盘点 | 20% | 对象清单、风险SQL清单、兼容性报告 |
| 数据层改造与演练 | 20% | 试迁移环境、迁移流程验证、数据校验方案 |
| 应用与SQL改造 | 30% | 改写后的代码、单元测试和回归测试记录 |
| 业务验证与双跑 | 20% | 双跑方案、监控指标基线、问题清单 |
| 切换与保障 | 10% | 切换checklist、回退预案、值守记录 |
这个比例不是绝对的,但如果总工期只有三个月,那几乎必然意味着某个阶段被严重压缩。被压缩得最多的往往是"业务验证",而这恰恰是隐形陷阱爆发最集中的阶段。
6.3 风险预案:认识"可以接受的风险"和"不能接受的风险"
最后聊一下风险管理。迁移项目的风险不可能清零,能做的只有分级对待。我会把风险分为三类:
第一类是"可接受风险",比如一些低价值报表在切换初期的查询延迟比Oracle高了几十毫秒,这类问题不影响业务结果,可以记录后持续优化。第二类是"需高度关注风险",比如核心交易接口在高峰期的响应时间劣化、数据增量同步出现延迟,这类问题要设置自动告警,在SLA超限前人工介入。第三类是"不可接受风险",比如数据丢失、主键冲突、业务对账不平,这类场景必须有预定的紧急回退机制,且回退方案要经过演练验证。
风险预案的落点不是一份文档,而是可执行的checklist。我习惯把切换当天要做的每个动作都写成勾选项:谁负责停写两个库、谁负责执行增量追平、谁负责切换负载均衡、谁负责盯着监控大屏、出现问题后按什么顺序升级。每一步做完就勾掉,做到"多线程协作但不乱"。这个习惯在多次切换中都救了场——不是没出过问题,而是出了问题之后每个人都知道自己该干什么。
我个人做了这么多迁移项目,最大的体会是:Oracle数据库国产化替代能不能成,技术选型只占一小部分,真正决定成败的是团队有没有用足够务实的态度对待那些"隐性陷阱"。不要因为基础SQL跑通了就觉得万事大吉,也不要因为工具报告写着"兼容"就放弃人工审查。迁移不是搬数据,是搬思维。把评估做细、把改造做透、把验证做全,这条路是走得通的。如果这篇文章能给正在做类似项目的你一些参考,哪怕只是提醒你多看一眼序列和触发器的兼容性,我就觉得值了。