1. 项目背景与核心问题梳理干数据库这块的人这两年应该都有同一个体感Oracle 替换这件事已经从“要不要做”变成了“怎么做”。我接手这个项目的时候客户的核心诉求就一句话——把跑了好几年的 Oracle 数据库平滑地换掉业务不能断数据不能丢性能不能崩。先说结论Oracle 替换工程真正难的从来不是数据库本身的切换而是围绕它生长出来的那一整套生态。你想想一套系统跑了好几年积攒下来的存储过程、触发器等对象业务代码里的 SQL 写法定时任务报表脚本甚至 DBA 日常运维的习惯全都长在 Oracle 的语法和特性之上。一旦底座换了这些积累要么跟着改造要么作废重来。所以我在项目启动的第一周没有急着选型也没有急着装环境而是先把所有涉及 Oracle 的系统过了一遍。这一步极度重要可以用一个词概括摸家底。你需要搞清楚下面这几件事。第一有多少存量对象。这包括表、视图、索引、序列、存储过程、函数、包、触发器、物化视图。每一项都要落到清单上标注好归属哪个业务模块被哪些应用调用。我踩过最大的坑就是前期盘点不全结果迁移到一半冒出一个只在月底结算才跑的定时存储过程导致整体进度延期了快两周。第二数据量到底有多大。这里要注意不能只看总容量还得看大表的分布、增长速率、归档策略。我曾经遇到过一个客户说好的数据总量 3TB结果迁移时发现光一张日志流水表就占了 1.8TB而且没有任何分区差点把迁移窗口直接拉爆。第三业务对可用性的要求。RPO恢复点目标和 RTO恢复时间目标必须和业务方确认到具体数字。有的核心系统能接受停机 4 小时有的连 10 分钟都忍不了。这直接决定了你后面选停机迁移还是在线同步方案。第四应用层的兼容性。你的应用是 Java 写的还是 .NETORM 用的是 MyBatis、Hibernate 还是纯 JDBCSQL 里有没有大量使用 Oracle 特有的函数这些决定了改造工作量的大头在哪。做完这轮盘点整个项目的边界、风险和改造量基本就有了一个比较清晰的轮廓。我个人的经验是盘点工作至少占到整个项目周期的三分之一千万别舍不得这个时间。前期摸得越细后期返工越少。顺便说一句网上关于“国产化迁移”的讨论非常多但落到工程实践上它就是一次很普通、很严谨的异构数据库迁移。别被概念唬住核心还是回归到数据、对象、应用、运维这四个维度去拆解问题。2. 方案选型思路与整体架构设计2.1 目标数据库是个选择题Oracle 替换成什么这个决策会直接影响后面所有的工作量必须慎重。拿我这次项目来说当时面前有三条路。第一条路是用开源的 PostgreSQL。它的兼容性在开源数据库里算不错的尤其是对复杂 SQL 和事务处理的支持很多从 Oracle 迁过来的开发者反馈学习曲线比较平缓。如果你的团队里有熟悉 PG 的人并且业务以 OLTP 为主这条路性价比很高。第二条路是用国内主流的国产数据库像达梦、OceanBase、openGauss 这些。它们大多主打对 Oracle 的兼容尤其是达梦语法层面做了大量适配连 PL/SQL 都能原样跑通大半。我这次选的就是达梦核心原因就是存储过程迁移成本极低能帮项目省下大量改写时间。第三条路是 MySQL。如果应用本身已经做了很好的数据访问抽象SQL 用得非常规范MySQL 也是一条路。但要注意Oracle 里很多习以为常的写法比如CONNECT BY递归查询、MERGE INTO、开窗函数MySQL 的支持度都有限改写工作量会显著上升。没有绝对正确的选型只有适不适合当前业务场景的选型。我的建议是拉一张对比表把语法兼容度、团队熟悉度、运维成熟度、商业支持这几个维度放进去打分用数据来说话。毕竟不同行业的业务特征差别很大金融、政务、制造业各自对一致性、并发、容灾的要求都不一样。2.2 四种迁移策略怎么取舍选型定了接下来是迁移策略。我在实践里总结下来主流的做法有四类各有各的适用场景。策略一双写迁移。应用同时写 Oracle 和目标库历史数据先灌进去然后通过数据同步工具把增量追上追平后切换读流量。这种方案 RTO 最短但对应用代码的侵入大需要在 DAO 层做双数据源路由。适合业务无法接受长时间停机的场景。我当时评估过如果要求停机小于 15 分钟基本只能走这条路。策略二全量增量切换。窗口期先做全量数据迁移然后开启增量同步等两边数据 Lag 归零后进维护窗口做应用切换。这是最通用、性价比最高的一种方式绝大多数项目最后都会落到这个模式上。关键是增量同步工具要稳断点续传能力得过关。策略三迁移回放验证。先把业务流量在 Oracle 上录一份同时在新库上回放对比结果。这种方式适合对数据一致性极度敏感的场景比如资金类系统。但实施成本高周期也长一般只在金融行业看到过。策略四一次性停机迁移。直接停应用、导数据、切流量。适合并发低、数据量小、能接受较长时间停机的内部系统。如果迁移窗口有 8 小时以上这其实是最省事的方式不用搭复杂的同步链路。从我这次项目的实践来看采用的是策略二的变体——全量迁移 增量追平 分批切流。核心系统放在凌晨业务低谷期切换外围系统提前一周已经切完这样整体风险被摊薄了不少。2.3 架构设计中的关键考量架构层面有几个点我觉得比选型和策略本身更值得拿出来聊一聊。第一异构数据库之间的类型映射要提前定义清楚。不要等到迁移工具报错了才去查文档。VARCHAR2、NUMBER、DATE、CLOB、TIMESTAMP这些在目标库里分别落到什么类型必须形成一张映射表作为整个迁移过程的基准文档。尤其是 NUMBER 类型的精度问题Oracle 里的 NUMBER 可以不带精度参数落到 PG 或达梦如果不做约束容易丢精度。第二应用访问层要做减法。这句话的意思是尽量把 SQL 中的数据库特有语法收敛到最小范围。我在项目中专门立了一条规矩新代码禁止使用任何数据库专有的函数和语法旧代码能改的尽量改。这其实是在为未来留后路别让下一次迁移再经历一次同样的痛苦。第三数据校验方案要前置。传统做法是迁移完了才开始比对发现不一致再返工非常被动。更好的做法是在迁移工具里直接嵌入校验逻辑——每迁完一张表立刻抽样比对行数和关键字段的校验值做到边迁边验。3. 核心对象迁移的具体实现3.1 表和索引迁移的实操路径对象迁移这块先说表和索引。这是所有后续操作的基础也是最容易出问题的地方。我常用的做法是三步走。第一步是用工具从 Oracle 里把 DDL 语句抽取出来然后基于先前定义好的类型映射表把 DDL 改写成目标库的语法。这里有一个非常实用的技巧不要手动去改几十张甚至上百张表的 DDL而是写一个脚本批量处理用正则把常见的关键字替换掉比如把VARCHAR2替换成VARCHAR把NUMBER(10)替换成BIGINT。批量做完后再人工审核差异效率能提升一个量级。第二步是处理表的物理属性。Oracle 的表空间、分区策略、存储参数这些在目标库里完全用不上但要留意分区表。如果原表有 RANGE 分区你要在目标库里重建对应的分区策略否则大表查询性能会急剧下降。第三步是索引的迁移。这一步最容易被低估。很多人迁移完表就把这事给忘了结果业务一跑慢 SQL 一片一片地冒出来。索引迁移不能简单复制要结合新的查询计划重新设计。Oracle 里的位图索引、反向键索引这类特殊类型目标库未必支持需要等价替换成普通 B-Tree 索引或者函数索引。另外还要多说一句外键约束的迁移顺序是有讲究的。必须先迁父表再迁子表不然数据导入的时候外键校验会直接把导入进程卡死。实践中我的习惯是先禁用所有外键约束等数据全部导完再统一启用并做一次完整性校验。3.2 存储过程、函数和包怎么改这一块是 Oracle 替换工程里最考验功力的部分尤其是存量系统里大量的 PL/SQL 逻辑。好消息是主流国产数据库的 PL/SQL 兼容度比很多人想象的要好坏消息是你永远会碰到官方兼容列表之外的东西。我这次项目碰到的第一个坑就是隐式游标。Oracle 的FOR rec IN (SELECT ...) LOOP这种写法在目标库里可以直接跑通但%ROWTYPE配合动态 SQL 的场景就涉及改写。给大家一个参考思路先跑一遍静态 SQL 语法检查工具把报错的地方聚集起来看一看。通常 60% 以上的报错集中在以下几类SYSDATE替换成目标库的当前时间函数NVL换成IFNULL或目标库对应的空值处理函数TO_CHAR的日期格式串目标库可能不完全兼容CONNECT BY层级查询需要改成目标库的递归 CTE 写法MERGE INTO的改写。改写存储过程时我一直坚持一个原则能不改就不改必须要改就改得彻底。什么叫改得彻底就是不仅把语法层面的东西改掉还要把逻辑上依赖 Oracle 特性的部分一并处理掉。比如在 Oracle 里你可以依赖SELECT ... FOR UPDATE的锁等待行为但在目标库里锁机制可能有差异这种隐性问题不处理上线后并发一上来就会出事故。另外强烈建议做一次PL/SQL 静态代码扫描把可疑的语法点和死代码标出来。不要过于相信人工代码 review几十个存储过程靠人一双眼睛盯漏掉一两个隐患太正常了。3.3 分页、字符串处理这些高频场景的兼容项目里总共排查出来一千多处 SQL 语句其中占比最高的是分页查询和字符串处理。这两个场景虽然简单但改写量巨大值得单独说道说道。Oracle 的分页依靠ROWNUM经典写法是三层嵌套子查询。迁到目标库后MySQL 用LIMITPostgreSQL 和达梦可以用LIMIT OFFSET代码整体简洁很多。我这边整理了一个对照关系大家可以参考Oracle 写法目标库通用写法WHERE ROWNUM 20LIMIT 20WHERE ROWNUM BETWEEN 11 AND 20LIMIT 10 OFFSET 10ORDER BY col OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLYLIMIT 10 OFFSET 10需要注意的是Oracle 的ROWNUM是在排序前生效的所以对于深分页场景原本的性能逻辑本质上是有问题的。迁移其实是一个很好的契机把深分页改成基于游标或者基于WHERE id ?的键集分页。这个优化能显著降低目标库的压力我在项目里顺手改造了十几个高频分页查询上线后响应时间降了一半以上。字符串处理这块Oracle 的INSTR、SUBSTR、REPLACE、LPAD/RPAD在不同数据库里的行为差异很大。尤其是字符串截取的位置计算Oracle 的下标从 1 开始这和其他语言一致但某些数据库的字符串类型处理空值和超长字符时行为不一样。我自己就遇到过一个非常经典的坑一个字段存的是手机号Oracle 里定义为VARCHAR2(11)到了目标库改成VARCHAR(11)居然报超长。查了半天才发现源端数据里有不可见字符迁移后字符集处理方式变了导致实际存储字节数超了。后续专门加了一个清洗任务把所有字符字段统一过了一遍剔掉不可见字符和控制字符。还有一个高频问题是字符串转数字的过滤。Oracle 里你可以依赖隐式转换或者用正则表达式来筛掉非数字字符串。但目标库的隐式转换规则更严格一个非法字符直接就把语句打挂了。我的建议是所有从字符串字段提取数值的逻辑一律显式写成WHERE REGEXP_LIKE(col, ^[0-9]$)不要依赖数据库的隐式转换。这个习惯能帮你避掉大量上线后的数据错误。4. 数据迁移与校验机制4.1 全量迁移工具链的选择与配置数据迁移工具选型上我这次没有用看起来很炫的第三方商业同步软件而是选择了数据库自带的工具加上一批自己写的脚本。原因是国产数据库的配套工具这两年做得已经比较成熟导入导出的效率完全够用而且省的维护成本很低。以达梦为例dmfldr工具做批量导入非常快千万级别的表跑几分钟就能导完。我这里给一个实战思路先用工具把 Oracle 的数据导出成文本文件再做字符集转换然后用数据库的批量导入工具灌进去。有人可能觉得脱裤子放屁多此一举但实际上这种离线文件方式最大的好处是可断点续传出错能定位到具体行比 JDBC 直连导入要稳太多。导入之前有件事必须要做先检查目标端表的约束状态。把所有外键、唯一约束、非空约束全部先禁用导入完成后再启用。不然导入过程中任何一条数据不满足约束整个批量任务就挂了又得从头再来。另外大表导入时请务必把事务批量提交比如每 5000 行提交一次否则一个超长事务跑完回滚段的压力会把数据库拖垮。并行度设置稍微提醒一下。不是导入工具开的线程越多越好我这次刚开始设了 16 并发结果直接把目标库的 IO 打满了业务侧延迟飙升。后来降到 8 并发让导入和数据写入磁盘之间形成一个相对均衡的状态整体反而更快。每个环境硬件不一样建议先用一张中等大小的测试表跑几轮测量出接近硬件能力上限的并发值再正式跑全量。4.2 增量同步的链路搭建与延迟控制全量迁移只是把历史数据搬过去真正让系统能平滑切换的是增量同步链路。这一节要稍微详细一点因为这里面的坑太多了。增量同步的方案一种是用数据库自带的物化视图或者日志抓取机制另一种是用第三方工具做基于日志的分析同步。我这次的项目的做法是通过目标库自带的增量同步组件去抓取 Oracle 的 redo 日志并解析成目标库的 SQL再应用到目标端。这个方案听起来简单实际上链路里有很多细节。比如 Oracle 的日志格式非常复杂日志抓取组件偶尔会漏掉某些特定类型的 DDL 操作。我建议所有结构性的变更都走运维平台登记禁止业务方在生产库上直接执行 DDL这样才能保证增量链路的稳定性。延迟控制上最实用的手段就是搭一个监控页面实时展示两端同步延迟。我自己是写了一个小脚本每 30 秒去源端和目标端各跑一次SELECT COUNT(*)或者查一下最大时间戳字段算出差值画成曲线。延迟一旦超过阈值立刻告警。这不是什么高科技但非常管用。上线前两周我每天都盯这个数字确保在切换窗口内延迟降到 5 秒以内才开始切流量。4.3 数据校验到底应该怎么验数据校验这个环节项目组内部吵过不少次。有人觉得简单 count 一下就行了有人坚持要逐行比对。我的结论是行数比对只是起点真正需要的是多层校验体系。第一层是行数校验。每一张表迁移前后 count 对一遍这张表如果对上只能说明两边记录数一致不能代表内容一致。第二层是抽样内容校验。对大表按主键做抽样比如抽 5%对抽取出来的每一行做哈希校验。密码学哈希是一个很好的选择把每一行的所有字段拼接起来算一个 MD5 值两侧对比。抽样占比可以根据表的重要程度调整核心交易表直接 100% 全量比。第三层是业务指标校验。这一层很容易被忽略但恰恰是最有价值的一层。我在项目里列了几十个关键业务指标比如用户总数、今日订单数、账户余额汇总、累计交易笔数迁移前后跑同一套统计 SQL对比结果。这个方法能从业务视角验证数据是否真的没有错而且业务方看得懂、信得过比技术层面的校验更有说服力。校验脚本的编写有一个建议不要只在迁移当天跑一次。切换前连续一周每天固定时间点跑一遍形成数据快照。这样能发现那些只在特定业务周期才会出现的问题比如月末结算、季末计提、零点定时任务产生的数据变化。5. 应用改造与切换实施5.1 连接层改造与数据源切换应用改造的第一步就是连接层。这一步听起来非常基础但实际做起来很容易翻车。Oracle 的 JDBC 连接串是jdbc:oracle:thin://host:port/service_name换成目标数据库之后驱动包要换连接串格式也要换。这些都好办真正麻烦的是连接池的配置参数。Oracle 的连接池参数和目标库完全不一样比如 Oracle 的连接数、会话数、游标数这些指标到了目标库可能需要完全不同的配置策略。我这边建议先搭一个独立的环境然后把应用整个部署一套只把数据源指到新库上用压测工具把高频接口全部打一遍。这一步的目的不是为了测性能而是为了把连接层的问题提前暴露出来。比如我用过一个应用连接池配置了maximumPoolSize50但在新库上 50 个连接直接超过了最大会话数限制应用启动后一堆报错查了半天才定位到是连接池参数适配的问题。数据源切换的过程中另一个需要处理的问题是分布式事务。如果你的系统里存在跨库事务比如应用同时连着Oracle和一个MySQL切换时这些事务的处理就会变得异常复杂。我的建议是尽量在架构层面规避掉跨库事务把涉及多数据源的逻辑通过应用层补偿或者消息队列来处理。为了一次迁移去引入分布式事务中间件风险和成本都太高。5.2 应用代码改造的几个硬性原则代码改造是 Oracle 替换工程里工作量最大的一块也是最容易失控的地方。我总结了几条硬性原则供大家参考。第一先跑后改。不要拿着代码文档凭空想象先把应用在测试环境跑起来让 SQL 报错炸出来再用错误日志去定位修改点。这样效率最高也能覆盖到很多静态代码扫描发现不了的动态 SQL 问题。动态 SQL 拼接是代码改造的重灾区尤其是 MyBatis 的 XML 里写ROWNUM、SYSDATE这类函数静态扫描经常漏掉。第二统一收口。所有 SQL 的修改必须经过统一的数据库访问层不允许在业务代码里散落各种裸 SQL。我之前接手过一个系统代码里有大量JdbcTemplate.queryForList的裸 SQL改造时每一处都要人工核对数据库兼容性活活多花了两周时间。第三分批改造灰度切换。我按业务模块的边界把系统拆成了 A/B/C 三个批次。A 批先切跑一周观察稳定性和性能B 批跟上C 批最后。这样即使出问题也能快速定位到是哪个模块的锅回滚成本也低。强行一天之内全量切换的我基本没见过顺利收场的。改造过程中还需要关注一个隐蔽的问题——序列。Oracle 的序列是通过SEQ.NEXTVAL获取目标库的序列语法可能略有区别比如NEXTVAL FOR seq或者是seq.NEXTVAL。这个通常在代码里很好替换但要注意序列的步长和缓存设置如果两侧对不上上线后主键冲突问题会让人焦头烂额。5.3 切换演练与回滚方案切换演练这件事怎么说都不为过。我们组内部的原则是没有演练过三次以上的切换流程不允许上生产。第一次演练的目标是跑通流程。你会发现各种意外比如切换脚本里有个 SQL 漏改了一个 schema 名称、某个存储过程少了授权、某个应用没改数据源。第一次演练的混乱是正常的关键是把它当成一次完整的彩排把问题全部记录下来。第二次演练的目标是验证时间窗口。我这边定的是 2 小时全量校验 增量追平 应用切换 冒烟测试必须全部完成。如果超时了就得回滚。很多团队忽略了这个指标结果真到切换当天发现时间不够手忙脚乱之下做出了错误的决策。第三次演练是故意制造故障。比如在切换过程中停掉一台应用服务器或者手动断开同步链路看看监控告警能不能正常触发。这种混沌工程式的演练能帮你把最坏情况下的应对方案想清楚。回滚方案这块我的经验是准备三层。第一层是数据库层回滚切换前对目标库做一次全量备份如果切换后数据不一致直接从备份恢复保证能回到切换前状态。第二层是应用层回滚保留旧版应用包切换后如果发现严重问题直接重新部署旧包。第三层是网络层回滚如果应用和数据库之间用了中间件或者网关可以根据流量切回源端。制定了回路方案之后一定要演练别等真出事了才去翻文档。6. 性能调优与生产保障6.1 迁移后的性能问题从哪找数据和应用都切过去了数据库迁移工程只是完成了 80%剩下 20% 全是性能问题。上线后第一周最常收到的反馈就是“某个页面比以前慢”“某个报表跑不出来了”。这些问题的根源绝大多数不是目标库不行而是SQL 写法还停在 Oracle 时代的习惯。我处理性能问题的标准流程是先接慢查询日志把所有执行时间超过阈值的 SQL 捞出来然后逐条分析执行计划定位到是全表扫描、索引失效还是行估算偏差导致的错误计划最后针对性地做 SQL 改写或者索引优化。举一个很典型的例子。Oracle 里很多人习惯写WHERE SUBSTR(col, 1, 3) ABC或者WHERE TRUNC(create_time) TRUNC(SYSDATE)这种写法在 Oracle 里也能用到索引或者因为基数估算准确所以性能可以接受。但到了新库这种函数套在列上的写法索引基本就失效了。我这边改写成WHERE col LIKE ABC%或者WHERE create_time ? AND create_time ?之后同样的 SQL 直接从全表扫描变成索引范围扫描响应时间下降了两个数量级。另外要关注统计信息的更新。新库刚迁移进来的数据优化器对数据分布的感知可能很弱。迁移完成之后立即对所有涉及的表执行一次全量统计信息收集这是一个成本很低但收益极大的操作。我见过有团队迁移完忘了这步一个简单的关联查询走错执行计划把数据库 CPU 直接干到 100%。6.2 参数配置与基础环境调优目标库的参数配置不能照搬 Oracle 的经验也不能完全用默认值。比如内存参数新库的共享内存、缓冲区大小、最大连接数都需要根据业务实际情况调整。我这里的建议是先跑基线压测用数据说话。拿业务高峰期的流量做一次回放压测观察数据库的关键指标——CPU、内存、IO 延迟、连接数。然后根据压测结果逐个调整参数再进行下一轮压测。两周时间能把参数调到一个相对合理的状态。一个很容易被忽略的参数是最大连接数。很多应用上线之前DBA 用的是默认值结果业务流量稍微涨一点应用就连不上数据库了。这个参数一定要结合应用的连接池配置一起来看确保数据库侧的连接上限高于应用侧的总连接需求。还有自动清理相关的问题。Oracle 里有 UNDO 表空间来管理事务回滚数据目标库相应的机制不太一样。如果你发现新库的磁盘空间莫名其妙一直在涨大概率是版本清理没跟上需要检查对应的清理任务是否正常调度。6.3 长期监控体系怎么搭迁移项目的交付不是切完流量的那一刻而是系统稳定运行至少一个月之后。这个阶段监控体系的建设至关重要。我通常会从四个维度搭监控。基础指标CPU、内存、磁盘 IO、网络流量数据库指标连接数、活跃会话数、缓存命中率、慢查询数、锁等待时长业务指标核心接口的响应时间、吞吐量、错误率数据一致性指标每个小时跑一次关键表行数对比以及核心业务流水的一致性检查。告警阈值的设置我建议结合实际观察到的数据来定不要拍脑袋。先运行两周采集正常情况下的波动范围然后在这个范围之上设定告警线。比如正常状态下活跃会话数是 30-50那告警线设在 100 触发是合理的。如果业务高峰期本来就到 90那你把告警线设在 80 就是天天误报最后大家看到告警都麻木了反而是更大的隐患。还有一个容易被忽略但非常重要的环节和应用团队建立问题响应机制。数据库迁移后出现的问题很多不是数据库层面能直接定位的需要应用团队帮忙查日志、抓线程栈。提前建立一个值班群里面同时有应用、DBA、运维三拨人并约定问题分级的响应时间能省去上线后大量的扯皮时间。7. 常见问题与实战避坑7.1 字符集问题Oracle 的字符集编码和新库的字符集不一致是迁移中最常见的隐藏炸弹。表面上看数据导出导入都成功了行数也对但一到应用查询就会出现乱码或者报“字符串截断”错误。我这次项目的经验是导出的文件统一转成 UTF-8导入前检查一下目标库的字符集配置。另外不要只看数据库层面的字符集还要看客户端的NLS_LANG环境变量。很多奇怪的中文乱码问题最后定位到的原因都是导出机器的 NLS_LANG 和服务器的不一致。这里还有个进阶技巧迁移完一定要对文本字段做一遍乱码检测。比如可以写一个查询把含有非法 UTF-8 字节的内容捞出来。这个操作虽然不能完全避免乱码但能兜住大部分异常。7.2 序列与自增主键的坑表和数据都迁移完了应用一启动紧接着报警的就是主键冲突。原因基本都出在序列没有正确设置起点上。Oracle 的序列是独立对象你在目标库里新建的序列初始值可能还停在 1。如果旧表里的主键最大值已经到 500 万新序列下次取到的却是 1那必然冲突。这一步必须在数据迁移阶段一起处理读取每张表当前的最大 ID然后把对应的序列初始值设置到这个最大值加 1。更隐蔽的一个坑是序列的缓存值设置。Oracle 序列默认 CACHE 20目标库如果是 100 或者更高应用重启后序列可能出现跳号。有些业务场景对主键连续性有要求这就要提前沟通清楚把缓存值调到合适的水平。7.3 连接异常与监听问题应用切换后偶尔会遇到连接很慢或者连不上的情况。这里我可以提供一份排查思路按优先级从高到低走。检查防火墙和安全组规则确认应用服务器的 IP 端口是否放行检查数据库监听是否正常目标库的服务名是否配置正确检查连接串里的地址、端口、服务名有没有笔误注意不要漏掉下划线或大小写问题最后再查数据库自身的连接数和资源限制看是不是达到了上限。这些问题的排查黄金时间通常在切换后 30 分钟以内提前把检查脚本和常用命令准备好可以减少很多无谓的慌乱。7.4 慢查询的终极排查手段慢查询的排查我习惯按这个顺序来先看是不是统计信息过期更新统计信息再看执行计划确认是否走了全表扫描然后看索引设计评估是否需要建新索引最后看SQL 写法本身。80% 的慢查询都能在前三步解决剩下 20% 才是真正需要动 SQL 的。比较隐蔽的一类慢查询是绑定变量相关的。Oracle 对绑定变量的处理粒度比较粗新库可能对每个绑定变量值的敏感度更高。如果同一个 SQL 因为传入的参数不同导致执行计划差异很大那就需要考虑在 SQL 里加提示或者用更稳定的写法来固定执行策略。慢查询分析这块建议组里定一个制度每天花 15 分钟拉一下前一天的慢查询日志。坚持两周整个数据库的性能表现会有一个很明显的改善。这个习惯我保留到了现在凡是经手过的数据库都会保留这个例行检查的动作。8. 最终体会与收尾建议项目收尾时回顾整个过程我最想分享的一点是Oracle 替换工程它本质上是一场风险管理的实践而不是一个技术实现的问题。技术方案再完美如果没有把切换风险控制在一个可接受的范围内就谈不上成功。具体来说有几个动作贯穿了整个项目我认为是最终能平稳落地的关键。一是高密度的演练切换流程演练到形成肌肉记忆——什么先做、什么后做、出了问题按哪条路径处理全部刻在操作手册里。二是数据校验的层层深入从不放过任何一张表不放过任何一个校验维度用繁琐的检查换来内心的踏实。三是把应用团队拉进项目全过程让他们从一开始就参与改造和验证而不是临近切换才被通知要换数据库。技术再强也架不住业务方的恐慌和不配合。还有一个附加的收获是这次改造顺便帮客户理顺了一大批历史遗留问题。很多跑了多年的烂 SQL、没用的索引、不合理的定时任务在迁移过程中都被翻出来做了清理。从这个角度看替换工程也是一次难得的技术债务清理机会。最后再给大家一个非常实用的个人建议整个迁移过程记得把所有踩过的坑和对应的解决方案记录下来形成一份问题速查手册。我每做完一个项目都会整理一份下次再遇到类似的迁移查阅这份手册效率和信心都会提升不少。数据库迁移这一行经验是靠一个坑一个坑踩出来的整理成文档就是在给自己积累术。