社保系统割接——新老系统数据迁移的完整方法论
新老系统切换,不是写一条
insert into ... select from就完了。表结构不同、编码不同、两套系统的数据字典不同、迁移过程中业务还要停掉——这一切都要在一晚上内完成。这篇文章记录了一次真实的生产环境迁移:8个阶段的模块化迁移、DBLink跨库抽取、事前事后的对照校验、以及迁移后的补刀处理。
文章目录
- 社保系统割接——新老系统数据迁移的完整方法论
- 一、背景:两套系统,一张时间表
- 二、DBLink——跨库迁移的基础
- 三、迁移前检查——老系统的表哪些有数据
- 四、模块化分阶段迁移——8个阶段的严格顺序
- 五、迁移后的补刀处理——迁移完成只完成了80%
- 六、迁移全流程总结
- 七、这套方法论的关键决策
- 八、结语
一、背景:两套系统,一张时间表
老系统是独立部署的新农保+居民养老系统,跑了很多年。新系统是一体化的社保平台,要一次性接管两个老系统的全部数据。
割接的核心矛盾:迁移过程中业务不能跑——因为两边数据不同步,经办人在这边录了数据,那边迁过去了但少了这一条。所以必须选一个业务空窗期,停掉所有外围服务,在几小时内完成全部迁移。
迁移执行的完整时间线:
17:50 屏蔽报盘功能(停止银行扣款/发放) 17:50 屏蔽两个区的乡镇经办人员账户 17:53 清空新系统表结构,导入新表结构 导入配置表数据 18:22 暂停两个区所有经办人员账户 19:30 开始执行8个阶段的迁移脚本 ↓ 一、基础信息模块 ↓ 二、缴费数据迁移 ↓ 三、待遇发放模块 ↓ 四、个人账户信息模块 ↓ 五、财政补贴信息模块 ↓ 六、制度衔接管理 ↓ 七、银行模块 ↓ 八、最后的处理脚本 完成 恢复经办人员账户,恢复报盘功能迁移之前先做了两件事:屏蔽外围(银行扣款接口停掉,防止正在扣款的数据在迁移过程中变更),屏蔽经办人(所有经办账户加tem_前缀暂时冻结,防止有人在老系统上操作)。
二、DBLink——跨库迁移的基础
新老系统不在同一台数据库服务器上。老系统在172上,新系统在170上。迁移不是导出dmp再导入——是在新系统上建DBLink,直接从老系统跨库抽取:
-- 新农保老系统CREATEDATABASELINK hkxnb_linkCONNECTTOhkxnb_hk IDENTIFIEDBY"hkxnb_321"USING'(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.70.172)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = orcl) ) )';-- 居民养老老系统CREATEDATABASELINK hnjmyl_linkCONNECTTOhnjmyl_hk IDENTIFIEDBY"hnjmyl_321"USING'(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.70.171)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = orcl) ) )';两个Link分别指向两套老系统。迁移SQL在目标库(新系统)上执行,数据通过DBLink从源库直接抽取,不走导出文件,不走网络传输。性能瓶颈在源库的查询和网络带宽,不是导出导入的磁盘IO。
三、迁移前检查——老系统的表哪些有数据
老系统运行了很多年,有些表从建表就没有用过。如果不检查,一股脑全迁——迁了空表浪费时间,还可能因为表名在新系统的字典里不存在而报错。
-- 迁移中发现空的表AD59-- 财政补贴划拨到位信息 (空表)-- 该表与AD52(财政补贴划拨到位信息)相同,要查证确认AD59是空表,而且AD52有同样的数据。所以迁AD52就行,AD59跳过。迁移前的空表检查就是一次"数据资产盘点"——哪些表有数据、哪些是冗余表、哪些可能已经废弃。
四、模块化分阶段迁移——8个阶段的严格顺序
迁移按业务模块分为8个阶段,不是按字母顺序,是按数据依赖关系:
| 阶段 | 模块 | 迁移表数 | 为什么是这个顺序 |
|---|---|---|---|
| 一 | 基础信息 | ac01, ac02, ae03, af07, ce01, ac93, ac05, ac24, ac04 | 人员信息是所有后续表的父表,必须先迁 |
| 二 | 缴费数据 | ab54, ab11, ab10, ac10, ac11, ic50, ad21 | 缴费依赖人员信息 |
| 三 | 待遇发放 | ac90, ac63, ac79, ac71, ac61, ac75, ac76, ac77, ac82, ac83, ad34 | 待遇依赖缴费记录 |
| 四 | 个人账户 | ac50, ac51, ac53, ac55 | 个人账户依赖参保信息和缴费 |
| 五 | 财政补贴 | ad52, ad53 | 补贴依赖缴费和待遇 |
| 六 | 制度衔接 | ic03 | 衔接需要基础信息已就位 |
| 七 | 银行模块 | dk01, dk02, df01, df03 | 银行代扣代发依赖缴费 |
| 八 | 收尾处理 | 最后的处理脚本 | 以上全部迁移完成后执行 |
每一阶段只迁该模块的表,迁完做一次简单的计数校验(新系统的记录数和老系统的记录数是否一致)。确认无误后再进入下一阶段。如果有误——停在这里排查,不入下一阶段。
为什么银行模块没有导入?在迁移执行中,第七阶段"银行模块"标注了"没有导入"。因为银行代扣代发数据涉及外部系统的报文交互,报文格式、序列号、时间戳在新老系统之间不完全兼容。这种数据不能直接迁——要在新系统上重新生成。
五、迁移后的补刀处理——迁移完成只完成了80%
所有数据迁完后,还有一批因为数据格式变化、编码标准不同、管辖区划重新划分等原因需要单独处理的数据:
-- 变更缴费组号-- 补缴缴费组号维护-- 待遇拨付通知维护管辖区编号-- 待遇补发待遇调整-- 征集ID变更管辖区编号-- updateAC82_aaz220_to_AC75.sql这些脚本的共同特点:不能批量写进迁移脚本里。因为它们是迁移后才暴露出来的问题——迁之前不知道有多少条受影响,迁的过程中发现这类数据异常没法停工去修。所以拆出来作为"第八阶段的补刀"——全部迁移完成后,统一运行这批修复脚本。
六、迁移全流程总结
准备工作 ├── ① 从源库导出表结构 → 导入目标库 ├── ② 导入配置表数据 ├── ③ 重新编译存储过程和视图 ├── ④ 建立两个DBLink(分别指向新农保和居民养老源库) ├── ⑤ 屏蔽银行报盘功能(防止外部数据变动) └── ⑥ 冻结经办人员账户(防止内部数据变动) 迁移执行(8个阶段按依赖顺序) ├── 一、基础信息模块 ├── 二、缴费数据 ├── 三、待遇发放 ├── 四、个人账户 ├── 五、财政补贴 ├── 六、制度衔接 ├── 七、银行模块(本次未导入) └── 八、收尾处理脚本 迁移后 ├── 恢复经办人账户 ├── 恢复报盘功能 └── 补刀脚本(修复迁移中发现的边缘问题)七、这套方法论的关键决策
1. DBLink直抽不走文件。不导出dmp、不压缩、不传FTP。两套库之间的网络是内网,DBLink的吞吐量远高于导出导入。一张百万记录的表,insert into target_table select * from source_table@dblink几分钟完成,导出再导入要十几分钟。时间窗口就这么几个小时,每省一分钟都是在抢。
2. 依赖顺序驱动。不是按表名字母序,是按"这张表的数据被谁依赖,谁依赖它就放在前面"。基础信息是所有表的父表,必须第一个迁。如果反过来——先迁缴费再迁人员信息——外键约束会全部报错。
3. 银行模块本次不迁。不是疏忽,是外部系统对接数据不适合直接表级迁移。银行代发代扣的报文格式、批次号生成规则、对账序列号——这些都是新系统自己的逻辑。迁了数据但新系统生成的报文格式对不上,银行那边解析失败。与其冒险,不如在新系统上重建。
4. 补刀脚本独立。迁移脚本是"标准数据一键迁移",补刀脚本是"发现一个修一个"。不能混在一起——把补刀逻辑写进迁移主脚本里,以后排查问题时分不清是迁移的问题还是补刀的问题。
八、结语
系统割接的数据迁移,核心不是SQL写得好不好,是流程设计和时间窗口管理。8个阶段的顺序谁先谁后、哪些外围服务必须停、哪些数据不能批量迁要手工修——这些不是在数据库面前想出来的,是在割接的计划文档里一条条列出来的。
这套方法论从那次割接之后成为了后续所有迁移项目的标准模板——不是因为写得好,是因为每个步骤都在生产环境里验证过,没出过数据事故。