news 2026/10/1 22:38:47

Oracle替换工程实践:从资产盘点、SQL改造到割接踩坑全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Oracle替换工程实践:从资产盘点、SQL改造到割接踩坑全解析

接手过Oracle替换工程的人都知道,真正难的从来不是"把数据倒过去",而是"让整个系统无感地搬过去"。刚接到任务时,你面对的往往是一个运行多年的Oracle库,后面挂着一堆应用、报表、定时任务、存储过程,还有各种年久失修的"祖传脚本"。"替换"这个词听起来只是一次数据搬迁,做起来才知道,这是一场涉及SQL方言、事务语义、字符集、排序规则、连接池、监控告警的全链路手术。

下面我想把几轮Oracle替换工程里从技术选型、资产盘点、SQL改造到最终割接的完整实践拆给你看,包括那些文档里不会写、但真实生产环境必然遇到的坑。如果你正打算做Oracle替换,或者刚被拉进一个迁移项目,这篇文章至少能帮你少走一轮弯路。

1. 为什么要动Oracle:替换工程的真实起因与决策链条

1.1 办公室里的那个"不得不换"的理由

跟很多团队聊起Oracle替换,最初的动因往往不是技术,而是现实压力。我梳理下来,排在前三位的理由基本固定。

  • 授权与成本:Oracle的License按CPU核数算,随着服务器从小型机转向x86,核数翻倍,账单一涨再涨。很多企业发现这笔钱已经养不起第二套灾备了。
  • 服务响应不可控:Oracle的排障高度依赖原厂,遇到一个诡异的等待事件,社区资料少,工单排队时间长,一拖就是好几天,业务方等不起。
  • 技术栈割裂:新项目都在用PostgreSQL、MySQL或国内数据库,老系统用Oracle,团队两头都要养,招聘、培训、工具链全都要双份开销,日子过得很别扭。

这三个理由放在一起,替换就从一个技术命题变成了经营命题。而你作为执行层,真正要做的不是争论换不换,而是把"换得起、换得稳"这件事做实。这里顺带说一句,替换的启动信号经常是"领导换了"或者"预算砍了",但落到具体执行时,技术方案永远要自己拿得出手,不能指望外部驱动替你做判断。

1.2 决策前必须回答的问题清单

替换工程最忌讳上来就查语法差异,先把边界和约束谈清楚。我建议无论谁拍板,下面五类问题必须有明确答案,否则做出来的方案必然是空中楼阁。

  • 替换范围:是整个核心库一把梭,还是先挑几个非核心业务库试点?范围决定风险,也决定你要盘点的对象数量级。
  • 停机窗口:业务方能给多长的停写窗口?是半夜两小时,还是周末四小时?这直接决定增量同步和数据校验方案。
  • 数据体量:单表最大多少行、总体积多少T、日增多少?别凭感觉估算,去查dba_segments和dba_tables拿真实统计数字。
  • 改造责任边界:应用方愿意投入多少人力改SQL?DBA团队是否负责所有存储过程重写?权责不划清,后面互相扯皮一定会发生。
  • 回退条件:什么情况下必须回退?回退的SLA是多少?没有明确回退线的割接,本质上是在赌运气。

这些问题看着基础,但我在实际项目里见过太多次因为"先干起来再说"导致的返工。有一回,接手方以为只迁一个报表库,结果那个库下面挂了七个上游应用的直连账号,数据链路图一画,所有人都沉默了。所以,决策清单这一步永远值得花时间。

1.3 敢于说"不换"的边界

当然,替换不是所有场景的最优解。我见过一些小团队,Oracle总共就三个库、几十张表、没有存储过程,这种规模硬要折腾开源或国内数据库替换,迁移成本反而高于几年的License费用,纯粹是给自己找事。

我判断一个系统是否值得替换,会先看三件事:生命周期预期、复杂度、团队的长期投入意愿。如果系统本来就在技术债里挣扎,上面也没有资源投入改造,那替换工程大概率会变成一场漫长的消耗战。这时候,最专业的声音恰恰是"现在不换"。把决策依据写清楚,等业务方真正有动力时再启动,才是对所有人负责。

2. 迁移前的资产盘点:把隐形的Oracle依赖全部翻出来

2.1 从元数据开始:拿到完整的对象清单

资产盘点第一件事,是登录Oracle把家底摸清楚。不要只盯表和数据量,那只是冰山一角。我习惯先把dba_objects按类型拉一个全量清单,筛出自己负责的schema下面的表、索引、视图、物化视图、同义词、序列、包、存储过程、函数、触发器、DBLINK、JOB。

SELECT object_type, COUNT(*) cnt FROM dba_objects WHERE owner = 'APP_SCHEMA' GROUP BY object_type ORDER BY cnt DESC;

这一步会非常直观地告诉你改造工作量分布在哪儿。有的库几百个存储过程,有的库几十个物化视图,有的库重度依赖DBLINK做跨库查询——这些都会在后续方案里变成不同的处理策略。

然后是明细清单。每类对象都要导出定义文本;存储过程、函数、包、触发器用dba_source,视图和物化视图用dba_views,表结构用dba_tab_columns配合dba_constraints、dba_indexes。把这些导出成文本文件放进版本管理仓库,这就是后续所有改造工作的基线。数据库侧配置基线也要一并记录:监听端口、初始化参数、补丁版本、字符集、排序规则,这些看似跟数据无关,后面排查兼容性时全都用得上。

2.2 SQL文本与应用依赖:别漏了藏在代码里的SQL

光有数据库侧的对象清单还不够,很大一部分SQL不在数据库里,而在应用代码、报表工具、ETL脚本里。Oracle的v$sql只能看到运行过的SQL,如果有些SQL半年没跑过一次,它就不会出现在v$sql里,但替换之后一旦被触发,就是一颗定时炸弹。

我的做法是四路并查。第一路,从AWR和v$sql里拉最近半年执行频率高、消耗大的TOP SQL。第二路,在应用代码仓库做字符串全局搜索,凡是出现SELECT、UPDATE、DELETE、MERGE、FROM、JOIN关键字的文件全部列出来。第三路,把报表工具的后台SQL脚本也搜一遍,很多报表工具的连接串和SQL都写在配置文件或数据源定义里,非常容易漏。第四路,跟应用方团队做一轮"灵魂访谈",让他们回忆有没有夜间批量、年终处理、历史数据归档这种低频任务。

这四路并查做完,得到一份完整的应用SQL清单。拿这份清单去和目标库做语法兼容性扫描,能提前发现大部分改造点。需要说明的是,高频SQL适合用自动化工具批量扫描,低频批量任务则更依赖人工梳理,两边的比重要根据系统特点调整,不能一个模板套到底。

2.3 依赖关系与风险分级

盘点完成之后,把所有对象和SQL按改造成本和风险分四档。

风险等级判定依据典型示例处理策略
低标准SQL,工具可自动转换简单SELECT、INSERT、UPDATE自动改写+回归测试
中涉及函数、类型映射差异NVL、TO_CHAR、日期运算人工改写+针对性测试
高依赖Oracle专有特性或PL/SQL复杂逻辑存储过程大批量游标、自治事务、物化视图刷新重写为主,安排专项评审
极高紧耦合Oracle运行时行为依赖序列预分配、依赖空字符串等于NULL、依赖DBLINK级联查询需要业务方参与确认语义

这个矩阵的好处是让团队知道精力往哪里投。大部分项目里,真正难啃的是高和极高这两档,它们往往只占20%的数量,却要吃掉80%的工作量。把低风险那部分先跑通,能快速建立信心,但不要因为低风险改起来顺就放松警惕,后面的大头在存储过程和复杂SQL上。

3. 目标库选型与全量增量同步方案

3.1 选型不是找"最好的数据库",而是找"最能接住Oracle的"

选型时的评估维度我一般看五个:SQL方言兼容度、迁移工具成熟度、增量同步能力、周边生态和团队熟悉度、长期维护成本。

维度PostgreSQLMySQL达梦DM8openGaussOceanBase
SQL兼容度中等,需改分页/函数/过程较低,迁移工作量大Oracle兼容模式较好,支持包/游标改写兼容部分Oracle语法,对plpgsql不熟需适应兼容部分MySQL/Oracle语法
迁移工具pgloader、ora2pg、自研手动为主,需大量改写DM数据迁移工具,支持Oracle直连自带工具相对较新OMS提供迁移链路
增量同步逻辑复制、DebeziumBinlog CDC成熟DM工具支持增量尚在完善OMS成熟
社区资料丰富非常丰富国内技术社区增长较快社区和文档增长快文档完善,大厂案例多
许可证开源免费开源免费商业授权开源有社区版/商业版

这个表不是标准答案,每个项目都要按自己的数据特征打分。我的经验是:如果Oracle里存储过程、包特别多,达梦的兼容模式能省掉不少PL/SQL重写的体力活;如果团队本来就熟MySQL,用MySQL也不是不行,但SQL改造量和存储过程重构会非常大。PostgreSQL是一个折中方案,语法接近、开源生态好,工具链复用度高。

还有一点很重要:选型时要让目标库厂商或开源社区的技术支持离你足够近。生产级割接不是写完SQL就结束,后面还有半年的稳定期,碰到性能问题和诡异的兼容性坑,一个能快速响应的人比什么宣传材料都有价值。

3.2 结构迁移:建表语句的差异和常用映射

把Oracle对象搬到新库,结构迁移是最先做的。数据类型映射是第一个坎,我列一个常用对照表。

OraclePostgreSQLMySQL注意点
NUMBER(p,s)NUMERIC(p,s)DECIMAL(p,s)无精度约束的NUMBER,MySQL要评估是否用DECIMAL(65,30)或拆成BIGINT
VARCHAR2(n)VARCHAR(n)VARCHAR(n)Oracle的n是字节数,MySQL的n是字符数,长度规则不同
DATETIMESTAMPDATETIMEOracle DATE包含时分秒,MySQL DATE只有日期,容易踩坑
TIMESTAMPTIMESTAMPDATETIME(6)精度差异影响比较运算
CLOBTEXTLONGTEXT注意索引限制和排序行为
BLOBBYTEALONGBLOB应用读取方式可能变化
序列SEQUENCE / IDENTITYAUTO_INCREMENT / SEQUENCE需要显式处理nextval语义

还有一个容易忽略的点是DDL语句本身。Oracle的CREATE TABLE在目标库可能需要调整表空间、分区策略、约束命名规则。分区表尤其麻烦,区间分区、哈希分区、列表分区的语法与PostgreSQL/MySQL差异都不小,手工一个个建容易出错。我建议对分区表单独评估,生成一套目标库风格的分区DDL,并提前做数据分布测试,不要等到割接当天才发现某个大表的分区定义有问题。

3.3 数据迁移:全量导入导出与并发调优

结构迁完,进入数据迁移。全量导出阶段,我推荐优先用目标库迁移工具或Oracle自带工具导成中间文件,而不是写JDBC程序慢慢抽。比如用expdp导出,再在目标端用load/copy命令导入,既快又稳。如果目标库是达梦,DM数据迁移工具直接支持从Oracle实例拉数据,配置好源库连接和映射关系就能跑起来,省去中间文件这一步。

导入性能的关键参数包括:并行度根据源库和目标库的IO能力设置,一般在4到16之间;大表不要单条INSERT,用批量insert或者copy协议;先建表、导数据、后建索引和约束,能大幅节省时间;数据导入期间先禁用业务触发器,导完再开启。

校验这步千万不要只统计行数。行数一致但内容不一致的场景太常见了。我会做三层校验:第一层行数,第二层关键字段的checksum或哈希,第三层抽样对比,对每张表按主键取5%-10%的行做全字段比对。时间允许的话,还要执行一遍应用层校验脚本,用实际业务查询验证关键业务的返回结果。这里多说一句,checksum算法要选择值域大的,否则碰撞概率会让校验失去意义,实际项目中用CRC64或MD5效果都还行。

3.4 增量同步:日志解析与CDC方案

如果停机窗口不够做全量,就必须上增量。Oracle侧增量迁移的传统选择是GoldenGate,现在也有不少自研办法:从归档日志解析redo,或者通过触发器/时间戳轮询抽取增量。

需要提醒的是,用触发器做增量会有性能开销,生产大表慎用;用时间戳轮询要求业务表本身有可靠的更新字段,没有的话很容易漏数据。目标库侧接收增量,PostgreSQL可以用逻辑复制,MySQL用Binlog复制,达梦和OceanBase都有自己的同步工具。整个增量链路最好在切换前持续跑两到三周,每天对比源库与目标库的差异,确保延迟长期处于秒级,再考虑割接。

4. SQL与存储过程改造:替换工程里最容易翻车的主战场

4.1 分页改写:ROWNUM和ROW_NUMBER的两种典型场景

Oracle经典分页写法是WHERE ROWNUM <= ?配合排序子查询,还有ROW_NUMBER() OVER (ORDER BY ...)的分析函数写法。这两种在目标库的写法很不一样。

比如Oracle常见写法:

SELECT * FROM ( SELECT t.*, ROWNUM rn FROM ( SELECT id, name, created_time FROM app_user ORDER BY created_time DESC ) t WHERE ROWNUM <= ? ) WHERE rn > ?;

在PostgreSQL/MySQL里可以直接用:

SELECT id, name, created_time FROM app_user ORDER BY created_time DESC LIMIT ? OFFSET ?;

机械替换看起来很简单,但有个隐蔽坑:ORDER BY的排序规则。Oracle默认排序对大小写、空格和null的排序顺序与PostgreSQL/MySQL不同,分页如果依赖排序稳定,改完可能出现同一页数据重复或漏页。这个我在坑3里会具体展开。

如果原SQL大量使用ROW_NUMBER() OVER做分组取TopN,比如"取每个用户最近一条订单",改写时要小心窗口函数的语法差异。尽管现代数据库基本都支持,但partition by子句后面的order by字段解析顺序偶尔会有差异。我的建议是每改一条复杂SQL,都拿一套代表性数据去两边跑,肉眼对比结果集,不要只看执行成功就急着收工。

4.2 字符串处理和隐式转换差异

Oracle里NVL是最常用的默认值函数,在PostgreSQL里对应COALESCE,MySQL里也可以直接用COALESCE或IFNULL。看起来像是一个函数替换,但语义有细节:NVL只接受两个参数,COALESCE接受多个;参数类型不同时,Oracle和PostgreSQL的隐式转换规则也不一样。

另一个经典差异是空字符串。Oracle里空字符串会被当成NULL处理,比如WHERE name = ''实际上查的是name IS NULL。PostgreSQL和MySQL则严格区分空字符串和NULL。这就导致同一个应用在不同库上查询结果不一样,原来返回空字符串的字段,迁到新库可能返回真实空串,应用逻辑里如果判断的是NULL,就会走错分支。这类问题靠自动化工具很难发现,只能靠业务测试覆盖。

字符串替换类的函数,比如REPLACE(str, old, new)和REGEXP_REPLACE,在PostgreSQL和MySQL里也有,参数顺序基本一致。但MySQL的REGEXP_REPLACE在高版本才支持,低版本得用其他函数绕。还有substr和substring的索引起点差异:Oracle从1开始,MySQL的substring从1开始,但有些程序员习惯写substr(str, 0, n),在Oracle里会返回空串,在MySQL里会正常返回,这种代码迁移后行为反而"变正常",进而暴露出之前的业务bug,也是挺折磨人的事。

4.3 存储过程、包与触发器的逐项改造

如果Oracle侧有大量PL/SQL,这是整个替换工程里工作量最大的部分。PL/SQL的包(Package)机制在PostgreSQL里没有直接对应物,通常要把包拆成普通函数并加前缀命名;达梦兼容模式做得好一些,包可以直接迁移,但仍需逐段测试。

改造中常见的差异点包括:%TYPE和%ROWTYPE锚定类型在PostgreSQL里的支持有差异;隐式游标FOR循环写法类似但变量作用域和异常处理有差别;自治事务在PostgreSQL里没有原生机制,需要用dblink开新连接模拟或改写业务逻辑;异常处理的WHEN OTHERS和SQLCODE/SQLERRM都要重新映射错误码。

还有一个值得抓住的机会:Oracle里常见的逐行UPDATE在大数据量下性能很差,迁移到新库时正好可以改写成集合操作,一次UPDATE加JOIN的写法往往比逐行循环快一两个数量级。触发器也是重头戏,PostgreSQL的触发器支持度不错,但OLD/NEW记录的引用方式、触发函数必须返回TRIGGER等细节都不同;MySQL触发器没有Oracle那么灵活,复杂规则可能要挪到应用层。

我的策略是提前把PL/SQL所有对象导出,做静态扫描,把不兼容特性标红,再按业务模块分批重写。重写过程中保持一个原则:不改业务逻辑,只改语法和语义等价的写法,所有改动都要有前后对比测试记录。

4.4 序列、同义词、物化视图等周边设施的迁移

序列是替换工程里特别容易翻车的地方。Oracle的序列NEXTVAL和CURRVAL语义在目标库里不一定完全一致。PostgreSQL的序列也支持nextval,MySQL的AUTO_INCREMENT则会在批量导入时自动取max+1,如果业务代码显式处理过序列值,迁移后主键冲突分分钟发生。我见过一次事故就是因为批量导入时没把序列重置到正确位置,第二天凌晨批量任务一跑,主键撞车直接把割接后第一个业务高峰打崩了。这个案例我在第6章详细拆。

同义词在Oracle里用来隐藏schema或远程表,PostgreSQL没有同义词对象,一般通过视图、外部表或直接改SQL里的schema前缀来替代。DBLINK在PostgreSQL里由FDW承担角色,在MySQL里没有直接等价物,如果业务重度依赖跨库查询,方案设计时就要提前规划。

物化视图是另一个硬骨头。Oracle的物化视图刷新机制成熟,可以快速刷新、完全刷新、复杂刷新。新库的物化视图能力参差不齐,PostgreSQL原生物化视图只支持全量刷新,增量刷新要靠第三方或自研触发器维护。如果原库有大量秒级或分钟级刷新的物化视图,尽量给业务方提供改造选项:要么放松刷新频率,要么把物化视图的逻辑下沉到定时任务加增量表。

5. 生产级切换:从灰度割接到回退兜底

5.1 割接窗口设计:把停机窗口切成五段

割接那天的时间窗口是稀缺资源。我习惯把整个割接过程切成五段:预检、停写、全量补差、增量追平、应用切换。

  • 预检:切换前一两小时,检查目标库状态、主备延迟、磁盘空间、连接数等指标,全部绿灯才动手。
  • 停写:通知应用侧停止写操作,数据库侧必要时设置读写分离或直接拒写,避免增量数据继续变化。
  • 全量补差:把从第一次全量之后新产生的数据再导一遍,通常比第一次全量小很多。
  • 增量追平:停写后继续消费最后一小段增量日志,直到源库和目标库的行数、checksum完全一致。
  • 应用切换:修改连接配置,把流量从Oracle切到新库,业务验证通过后,割接窗口结束。

每一步都要提前设计验证标准。拿"增量追平"来说,不能只等延迟为0,还要对比每张表的行数和关键表的校验值。这里有一个血泪教训:当年第一次割接,延迟数归零,但实际还有半分钟的归档日志没解析完,切换后一查,少了几百条记录。后来我们改成"延迟为0后再观察5分钟,且连续两次采样一致才允许切换"。

5.2 应用切换的细节:连接池、配置中心与DNS

应用切换不是简单改一个jdbc.url。生产环境会有很多台应用服务器,连接池、配置中心、DNS、负载均衡都有可能成为切换点。我的建议是提前准备一份切换清单,列清楚每台服务器上连接串在哪个文件、密钥怎么轮换、配置中心的哪个key要更新,由专人逐项打钩。

连接池参数也要调整。Oracle连接池和RDBMS连接池的行为差异经常被忽略,比如最大连接数、连接空闲超时、验证查询。有一类经典问题:目标库的默认最大连接数远小于Oracle,应用用同一套配置连上来,瞬间打满连接池,直接雪崩。这个我在坑2里细说。总之,切换前要按新库的规格重算连接池上限和超时参数,别拿老配置硬套。

5.3 回退方案:老库不拆,至少保留N天只读

割接完成后,回退能力要保留一段时间。我的经验是,老库不要急着下线,至少保留7天,并保持只读验证状态。保留期间不是闲着,要做两件事:一是定期从新库反向抽取少量关键数据回写老库的比对表,验证两侧数据一致性持续成立;二是把老库的备份完整留档,一旦切换后的一周内出现重大问题,还能用LUN快照或回放日志的方式恢复。

回退的决策点也要提前定:什么时候必须回退?比如"核心业务成功率低于99%持续30分钟"或者"数据一致性校验出现不可修复差异"。到了那个点,不要犹豫,直接按预案回退。最怕的是团队在割接后发现一堆小问题,又不舍得放弃已经投入的大量工作,一边修一边顶着,最后越陷越深。

5.4 演练的频次与验收标准

生产级平稳迁移没有侥幸,全是演练堆出来的。正式割接之前,至少要完整演练两次。演练不是走流程,要真刀真枪做数据切换和回退,记录每步耗时,识别瓶颈。第一次演练通常是灾难现场,你会发现各种意外:某个数据导入脚本在2T的表上跑了5小时还没结束,某个应用连新库时因为SSL配置报错。

每次演练后更新割接手册。第一版手册可能写了大几十页,第二次演练时就能缩减一半,因为很多步骤已经脚本化、自动化。我的验收标准是:连续两次演练在预定窗口内完成,且回退演练成功,才允许申请正式的割接窗口。

6. 踩坑实录:四次真实故障的完整排查链路

6.1 坑一:增量同步延迟归零后又冒出的数据差异

这个坑是在一次割接演练中遇到的。当时增量任务显示延迟为0,源库和目标库的行数一致,我们正准备宣布演练成功,一致性校验脚本却报出某个核心表差300条记录。

排查链路是这样的:先看增量任务日志,发现最后一段归档日志在延迟显示归零后的3分钟才解析完成;再看数据时序,发现那300条记录集中在停写前1分钟内提交,属于大事务在日志中的提交记录晚于业务提交时间。也就是说,延迟为0只代表日志消费到某个位点,不代表所有已提交事务都已经被解析。

解决方案很简单:把"延迟为0"的判定改成"延迟为0并持续观察5分钟,且连续两次校验一致"才允许切换。这个规则后来写进了割接手册,排除了好几轮演练里的假绿灯。

6.2 坑二:应用连接池在割接后瞬间雪崩

这个坑发生在一次正式割接后的10分钟。应用切换到新库后,首页突然大面积报错,数据库连接数飙到上限,CPU被打满。

一开始所有人盯着数据库怀疑是SQL有问题,但看慢查询,没有明显的慢SQL,连接数却一直在涨。后来抓应用线程栈才发现,应用用的是Oracle时代的连接池配置,最大连接数2000,而目标库实例规格只有500的连接上限。应用启动后大量空闲连接被创建,又因为目标库的wait_timeout比Oracle短,连接被服务端断开,应用连接池不感知,继续把失效连接给业务线程,业务线程阻塞后重连,又制造更多连接,形成了雪崩。

排查链路是:数据库CPU高 -> 看连接状态发现大量TCP连接处于CLOSE_WAIT -> 对应应用线程栈发现大量等待获取连接 -> 回溯连接池配置发现最大连接数远大于库端上限 -> 重新按新库规格和QPS预估设置连接池参数 -> 加一层连接池初始化预热脚本 -> 故障恢复。事后复盘,其实切换前的演练里就该暴露这个问题,但演练时用的连接数较小,没触发。教训是:演练环境必须和生产环境规格一致,否则很多参数类问题根本测不出来。

6.3 坑三:字符集排序不一致导致的分页错乱

这是迁移后一次晚间业务反馈的问题:一个列表翻页到第3页,连续出现和第2页重复的数据,而且有的数据不见踪影。

一开始怀疑是分页SQL改写有误,拿SQL到两边各跑一遍,结果集数量一样,但取出来的行就是不一样。后来逐步比对,发现问题出在ORDER BY的排序规则上。原应用用的是ORDER BY user_name,Oracle默认按二进制或语言排序,PostgreSQL的默认排序则基于locale,大小写、重音、空格的处理都不一样。排序顺序不一致,分页按偏移量取数,自然出现重复和漏行。

解决方式是明确排序规则:给排序列加上COLLATE或转成一致的比较基准。比如PostgreSQL里可以显式使用COLLATE,或者在SQL改写时统一先做TRIM、LOWER处理再排序。这里特别要提醒的是,DISTINCT配合分页也会受排序影响,如果SQL里既有DISTINCT又有聚合函数,排序字段和投影字段的关系要仔细审。

6.4 坑四:批量导入漏了序列步长,第二天主键冲突

这个坑来自一位朋友带队的迁移项目,事故完整链条是:数据导入完成后,开发同事用insert做了冒烟测试,一切正常;第二天凌晨批量任务跑起来,大量报表生成任务直接报主键冲突。

排查发现,导入工具把全量数据导入目标库后,目标库的自增序列仍然停留在建表时的初始值。Oracle侧的序列在上线前早就被业务消耗到了几十万,导入数据本身不占序列位点,导入也没重置序列。当晚冒烟测试的少量insert恰好没触发冲突,等批量任务一上来,序列值从1重新开始,撞上了已存在的数据。

修复办法是导入后立刻按每张表的最大主键值调整序列:PostgreSQL用setval,MySQL手动更新AUTO_INCREMENT的值,DM也有对应的重置方法。我后来把这个步骤固化到数据迁移脚本里,作为全量导入后的必做项,再也没出过问题。这个坑的教训是:别把序列当小事,它跟数据迁移是同一件事。

最后再分享一个小技巧:割接前把所有关键脚本和手册放在一个离线文件夹里,打印一份纸质版放在机房和办公室各一份。真到了割接现场网络抖动、平台连不上的时候,一份离线文档能救全场的命。替换工程的本质是跟不确定性做对抗,你能做的是把每一层风险都提前拆开、演练、加固,剩下的交给纪律。祝所有正在做替换工程的朋友都能平稳落地。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 22:35:53

Flutter+OpenHarmony城市井盖地图App实战:从地图接入到应急调度

凌晨两点&#xff0c;值班大屏上跳出一条红色告警&#xff1a;东三环辅路某处井盖发生位移&#xff0c;倾斜角超过15度。按照以前的做法&#xff0c;值班员要先翻台账确认井盖编号和所属班组&#xff0c;再打电话联系附近巡查员去现场核实&#xff0c;运气不好这个流程能拖上一…

作者头像 李华
网站建设 2026/10/1 22:33:10

TCP选择响应机制深度解析:从SACK原理到Wireshark抓包实战

简介&#xff1a;这份资源是面向计算机网络课程学习者与TCP协议实验实践者的选择响应版本实现包&#xff0c;针对TCP可靠传输中的选择确认机制提供可运行的完整工程&#xff0c;适合正在完成课程大作业或准备网络方向面试的读者参考。压缩包共24个文件&#xff0c;约1.05MB&…

作者头像 李华
网站建设 2026/10/1 22:32:53

Android系统五层架构全解析:从Linux内核到应用层

我第一次正儿八经研究Android&#xff0c;不是从写Hello World开始的&#xff0c;而是被网上各种零散概念弄懵之后&#xff0c;翻到了官方那张分层架构图。当时盯着看了很久&#xff0c;每一层都是英文&#xff0c;每一层都似懂非懂。后来做了几年客户端开发&#xff0c;再回头…

作者头像 李华
网站建设 2026/10/1 22:32:01

数据结构复习路线:从链表到二叉树,动手实践是关键

说句实话&#xff0c;上个月重新翻出当年学数据结构时的笔记&#xff0c;我只记住了“链表”“栈”“递归”这几个词&#xff0c;真让我写个反转链表的代码&#xff0c;愣是盯着屏幕半天没动手。这种感觉太真实了——大学课堂上学的时候觉得都会&#xff0c;考试也应付过去了&a…

作者头像 李华