业务不停机!Oracle 在线迁移 KingbaseES 方案详解:KDTS 存量搬迁 + KFS 增量追平

前言

先问个扎心的问题:你们上次数据库迁移的窗口,约了多久才约下来?
我猜不少人的答案是------约了一个月,还没约下来。业务一句"周日晚上不能停",DBA 就只能接着等。好不容易窗口批下来了,新麻烦跟着来:导出俩小时、导入四个小时、建索引再俩小时,中间任何一步翻车,全部推倒重来,因为天亮了。

数据量小,熬一晚也就熬了。到了 TB 级,停机迁移这条路基本走死。

那有没有办法让业务一边跑、数据一边搬?有。这篇文章就聊金仓数据库的在线迁移:两个工具打配合,KDTS 搬存量,KFS(KingbaseFlySync)追增量。跑顺了的话,真正停业务的时间,就切换那几分钟。

@TOC

一、先想明白:这套方案到底怎么转的

打个比方。这事儿跟搬家一个道理:新房装修好了,你不可能让全家先出去住酒店,等东西全搬完再回来------等不起,也没必要。聪明的搬法是:大件儿一趟一趟往新家运,老房子里日子照过;最后剩点随身行李,找个上午一口气拎过去,半小时收工。

对应到数据库这边,"运大件"就是 KDTS 的活:把 Oracle 里已有的表结构、索引、约束、历史数据,整建制搬进金仓数据库。这个过程源端业务完全无感,该读读,该写写。

"随身行李"归 KFS 管。搬迁期间业务还在 Oracle 上写新数据,怎么办?KFS 时刻盯着 Oracle 的重做日志,谁插了一行、谁改了个字段,全记下来,回头在金仓那边按顺序重放一遍。

有个时序要点,先划出来:必须先启动 KFS,再跑 KDTS。顺序反了,存量搬迁期间的变更就没人盯着,等你发现少数据,哭都来不及。另外,存量和增量的交界处难免混进点重复,KFS 靠冲突处理策略兜住------这也是后文反复念叨"无主键表必须提前处理"的原因:没主键,连冲突都没法定位。

真正要停业务的,只有最后切换窗口里那几分钟。

二、动手之前,把 Oracle 端收拾利索

这一章没什么高深内容,但真值钱。事后追着排查数据对不上的,回头一看,十有八九是这步没做扎实。咱一条条过。

归档模式得先打开。KFS 吃的是 Oracle 重做日志,库跑在非归档模式,它连饭都吃不上,链路根本起不来。

然后是附加日志。默认 redo 里那点信息,定位不到具体某一行,增量同步得靠附加日志补齐:库级开一次,再给关键业务表加全列附加。这步别省,省下来的时间,后面数据对不上时会加倍还回去。

账号单独建。迁移一个、同步一个,分开管,出了问题好查,权限也好审计,互不背锅。

最要命的是无主键表。增量同步的 UPDATE、DELETE 全靠主键或唯一键定位行,一张没主键的表混在链路里,就是颗雷。处理办法就俩:要么补主键,要么确认它就是张纯日志表、不需要实时跟着走,直接剔出同步范围。

代码直接抄,SQL*Plus 里逐条执行:

sql 复制代码
-- 1. 确认归档模式
archive log list;
-- 若显示 No Archive Mode,需要重启实例切换(挑变更窗口做,别在高峰上手抖):
shutdown immediate;
startup mount;
alter database archivelog;
alter database open;

-- 2. 库级附加日志
alter database add supplemental log data;

-- 3. 关键业务表加全列附加日志
alter table ORDERS add supplemental log data (all) columns;
alter table ORDER_ITEMS add supplemental log data (all) columns;

-- 4. 同步专用账号(这里列的是常用项,完整清单以 KFS 文档为准)
create user KFS_SYNC identified by "Sync#2026";
grant create session, execute_catalog_role, select any transaction,
      select any table, select any dictionary to KFS_SYNC;
grant select on v_$database to KFS_SYNC;
grant logmining to KFS_SYNC;  -- Oracle 12c 及以上

顺手把家底也摸一遍:哪些表没主键、哪些表是大户,心里得有本账。

sql 复制代码
-- 无主键表清单(增量同步的雷区)
select t.table_name
  from user_tables t
 where not exists (
       select 1 from user_constraints c
        where c.table_name = t.table_name
          and c.constraint_type = 'P');

-- 数据量 TOP 10,用来估存量搬迁的时长
select segment_name, round(sum(bytes) / 1024 / 1024 / 1024, 2) as size_gb
  from user_segments
 group by segment_name
 order by size_gb desc
 fetch first 10 rows only;  -- 11g 及以下把最后一行换成 where rownum <= 10 的写法

摸完底,再算两笔土账。

磁盘账:目标端空间按源端数据量的 1.5 倍起步留。听着夸张?索引要地方、临时表要地方、大对象还要地方,等真不够用的时候,扩容可比预留难多了。

带宽账:千兆内网理论吞吐 118MB/s 上下,5TB 数据光在网络上传就得 12 个小时起。算完要是发现网是瓶颈,提前想办法------临时拉条万兆,或者分批、挑重点表先走。别等开搬了才干瞪眼。

三、KDTS:存量数据,整建制搬过去

KDTS 是金仓数据库配套的迁移工具,图形控制台,浏览器里点选就行:源端选 Oracle,目标端选金仓,勾库勾模式,配好线程数,开跑。表、视图、序列、约束、索引、注释,这些常规对象都包在它的能力范围内。出错行可以配"跳过并记录",也可以配"直接中断",跑完出一份迁移报告,哪些成了、哪些败了、败在哪儿,写得明明白白。

线程数给大方点。几十张表的任务,单线程和多线程跑下来时间差好几倍,没道理省这个。

类型映射估计是大家最惦记的。好消息:金仓数据库的 Oracle 兼容模式原生支持 number、varchar2、clob、blob 这一票常用类型,KDTS 默认映射基本同名直迁。少数类型要留个心眼,挑容易出事的说:

Oracle 类型 金仓端常见映射 搬迁时要注意什么
NUMBER(p,s) number(p,s) 不带精度的不定长 NUMBER 直接映射为 number,极端精度业务留意舍入行为
NUMBER(p,0) / INTEGER bigint 小整数列落成整型,省空间,索引也快
VARCHAR2(n) varchar2(n) 分清 n 是 BYTE 还是 CHAR 语义,存中文的表照抄数字,容易踩截断
CHAR(n) char(n) 定长补空格,比对逻辑留意尾部空格差异
DATE date Oracle 的 DATE 自带时分秒,金仓 Oracle 兼容模式下同样带,不丢时间部分
TIMESTAMP(n) timestamp(n) 带时区的版本映射为 timestamptz,两端时区参数要一致
CLOB / NCLOB clob 大字段多的表搬得慢,单独分线程更稳
BLOB blob 大对象按磁盘量预估,空间留够
RAW / LONG RAW blob LONG 系列是上古类型,能在源端先改掉就先改掉

剩下几个坑,提前念叨念叨。

序列是个暗坑。序列迁过去时带的是迁移那一刻的值,可存量搬完到正式切换之间,Oracle 那头序列还在往前走。等切完了,金仓这边序列落后一截,新数据一进来主键直接撞车。所以切换前必须把序列顶上去,具体放第六章清单里。

存储过程和包,是全程最吃人力的一块。KDTS 能自动转写大部分常用 PL/SQL,但 Oracle 那些特色写法------包体、自治事务、DBMS_* 一堆包调用、绕来绕去的 ROWNUM------经常得人肉改。建议对象迁完后,在 KStudio 里挨个编译一遍,报错的拎出来排期处理。工期往宽了留,这块比你想的费时间。

字符集提前对齐。源端 GBK 还是 UTF8,目标库初始化时就定死。工具有转码能力没错,可脏数据这东西平时不吭声,一到转码就集体冒头(别问我怎么知道的),提前定好规矩省得返工。

跑存量的时机也有讲究:挑业务低峰启动。大表的耗时主要耗在网络传输和目标端写盘上,高峰期跑,源端 IO 和同步链路抢资源,两头都慢,得不偿失。

四、KFS:增量追平,把延迟磨到零

KFS 干的事,一句话讲完:借助 Oracle LogMiner 解析重做日志,把源端的 DML 变更翻译成金仓数据库能执行的语句,按提交顺序在目标端重放。源端、目标端各装一套同步服务,一头管抓、一头管放,管理界面里链路状态和延迟都看得见。

存量搬完、KFS 开始回放积压增量之后,你盯两个指标就够了。

一个是延迟。正常剧本是断崖式下跌,然后慢慢趴到零附近。要是延迟死活降不下去,八成有无主键表在作妖------没主键的 UPDATE 到了目标端只能全列匹配,性能差好几个量级,一张表就能拖垮整条链路。

另一个是回放速率。增量产生的速度长期压过回放速度,说明目标端写不动了,去查目标库 IO、查同步服务的资源配置,别干等。

另外三件事,提前打预防针。

大事务,能拆就拆。迁移期间别一口气 update 几千万行,日志解析端处理大事务极吃内存,同步服务被撑挂,链路重来,前面等的时间全白费。真有大批量需求,拆成每批几万行,细水长流。

DDL,冻住。从 KFS 启动到正式切换,源端结构变更原则上别碰。中途加字段、改类型,链路接不接得住得看版本支持,没到切换那天,别在刀尖上玩花样。

归档日志,留够。增量追平那几天,清理策略的手别紧,KFS 要用的日志段一旦被删,链路就得重起,前面的等待全打水漂。等切完了再收紧,不迟。

五、校验这步,千万别偷懒

数据搬完、延迟归零,先别急着切。校验做扎实,切换那晚才睡得踏实------不然躺到一半,突然想起有张表没对数,爬起来开电脑的滋味,不好受。

实用的是三层,由粗到细。

先对总行数。两端各跑个 count,几秒钟的事。粗是粗,大问题先筛出来。

总行数对上了,再分桶比聚合值。按时间或主键范围切桶,比行数、比金额合计,差异能很快圈进某个时间段里。

最后抽明细。从差异桶里拎几十行,逐字段人肉比,定位到根因为止。

分桶比对的两端 SQL 长这样,注意口径必须一模一样:

sql 复制代码
-- Oracle 端
select to_char(trunc(create_time), 'yyyy-mm-dd') as day,
       count(*) as cnt,
       nvl(sum(amount), 0) as amt
  from orders
 where create_time >= date '2026-09-01'
 group by trunc(create_time)
 order by 1;

-- 金仓端
select to_char(trunc(create_time), 'yyyy-mm-dd') as day,
       count(*) as cnt,
       coalesce(sum(amount), 0) as amt
  from orders
 where create_time >= date '2026-09-01'
 group by trunc(create_time)
 order by 1;

两边数字对上,说明存量加增量这场接力没掉棒。还有个容易忽略的点:校验的时候,源端还在写呢。要么挑业务低峰、增量延迟贴近零的时候做快照式比对,要么等切换窗口数据冻结了再比。拿一个动着的数去对一个静止的数,比出差异也是自己吓自己。

六、切换窗口:真正要停的,就这几分钟

前面铺这么多,就是为了把停业务的窗口压到最小。切换当天,下面这张清单建议打出来贴在桌上,一项一项打勾------别靠脑子记,凌晨两点的脑子靠不住。

# 动作 通过标准
1 通知业务停写,应用置为只读或短暂停服 Oracle 端确认没有活跃的写入会话
2 等 KFS 延迟彻底归零 延迟为 0 并保持稳定,不再波动
3 终验:行数 + 聚合值快速复核 与切换前校验口径一致
4 推进金仓端序列到安全水位 所有序列当前值 ≥ Oracle 端对应值
5 应用连接串切到金仓,确认驱动和连接池 连通性测试通过,无驱动类报错
6 恢复业务,重点盯错误日志和核心交易 核心链路正常,无批量异常
7 Oracle 转只读保留,约定观察期 观察期内无回退需求,再安排下线

第 4 步序列推进的 SQL 贴在这儿,到时候直接用:

sql 复制代码
-- 金仓端:把序列顶到安全水位,避免切换后主键冲突
select setval('seq_orders_id', (select max(id) from orders) + 1000);

回退也得提前想好。切完别急着下 Oracle,转只读,至少留一周;应用的连接配置双份保留,金仓真出大事,一把就能切回去。讲究点的团队,会用 KFS 再搭一条金仓回 Oracle 的反向链路,切完两端继续互备,回退就是分钟级。代价是多养一套链路------划不划算,看业务分量。核心交易系统,我建议搭。

最后啰嗦两句

这套方案说穿了就一句话:搬家拆成"大件先运、随身最后拎",最耗时的部分业务无感,人工操作全压缩到最后几分钟的窗口里。

工具确实把体力活都干了,可迁移项目真正磨人的,从来不是点按钮------是那些没主键的表、不敢跑的大事务、存储过程里绕来绕去的 Oracle 写法,还有切换当晚一条条过清单的耐心。摸底做得越细,切换那晚就越好过。

祝各位一次切过,窗口十分钟,回去补觉。

相关推荐
这个DBA有点耶40 分钟前
从异步复制到MGR:MySQL复制机制的三层演进与选型框架
数据库·mysql·代码规范
SelectDB40 分钟前
把 JSON 埋点表迁到 Apache Doris VARIANT:一次完整排错记录
大数据·数据库·数据分析
小林ixn40 分钟前
用 SQLite + 大模型做一个 Text2SQL 小助手:从建表到自然语言查询的完整实战
数据库·sqlite
旺仔不是程序员40 分钟前
pg_trgm GIN 索引:PostgreSQL 正则、模糊与近似度查询的三合一加速器
数据库·后端·sql
SelectDB42 分钟前
联邦查询慢到不能用?查湖排错的 6 个现场,附可直接复制的命令片段
大数据·数据库·数据分析
SelectDB1 小时前
Apache Doris 高性能 Open Lake Variant 读写技术解析(含对比数据)
大数据·数据库·数据分析
SelectDB1 小时前
多表 Join 与实时更新:Apache Doris 建表、调优与验证全流程(附 ClickHouse 对照)
大数据·数据库·数据分析
小鱼,1 小时前
人大金仓V9系统表名字冲突,设置search_path不起作用
数据库·kingbase
鸽芷咕1 小时前
金仓数据库 TB 级迁移提速实战:KDTS 线程数怎么算、JVM 内存怎么给、参数怎么调
数据库