从Oracle平滑迁移到KingbaseES关系数据库,这句话在立项报告里只有一行,做起来却包含了结构转换、数据搬迁、应用改造、性能调优、切换演练一堆事。最近我参与维护的一套核心业务系统完成了这个迁移,前后用了几个月,踩了不少坑,也沉淀出一些方法。这篇就是这次实践的复盘,尽量讲清楚每个环节为什么这么做、有哪些值得注意的细节。如果你正在评估要不要从Oracle迁到KingbaseES,或者已经卡在某个兼容性报错上,这篇内容应该能帮你省下不少时间。
数据库迁移最容易被低估的恰恰是“平滑”两个字。单纯把几TB数据从一个库拷到另一个库,技术难度其实不高,难的是业务中断窗口可控、数据零丢失、切换后性能不滑坡,还得随时能回退。接下来的内容按项目推进的顺序展开,从对象盘点、策略选型,到结构和数据迁移,再到应用侧改造、切换演练和问题排查,每一段都是实际执行过的经验。
1. 迁移背景与整体思路拆解
1.1 迁移为什么选“平迁+改造”而不是推倒重来
很多传统业务系统的核心库都是Oracle,跑了好多年之后,往往面临几个现实问题:商业数据库的授权和运维成本越来越高;团队希望把技术栈统一到一套更容易掌控的数据库体系上;底层基础软件也希望逐步替换成自主可控的产品。KingbaseES之所以进入视野,是因为它对Oracle语法和PL/SQL的兼容度在同类产品里算比较高的,这意味着大量存量代码不用推倒重写,可以走“平滑迁移”的路子。
但“兼容度高”不等于“完全一样”。KingbaseES底层还是自研内核,只是提供了Oracle兼容模式,目标是让你已有的SQL、存储过程、数据类型尽量少改就能跑。所以实际项目里不可能靠工具点一下按钮就完事,必须把“平迁”和“改造”组合起来用。
我这次采用的分批迁移+整体切换策略,思路是:结构对象先用工具自动转换,数据和增量同步按业务模块分批推进,应用代码在回归环境里长时间验证,最后挑一个业务低峰期做正式切换。相比一次性全量搬迁,这种做法最大的好处就是风险被切割成小块,每一批都能独立验证,出了问题可以随时停下,不会把所有隐患都留到切换当天。
1.2 三种迁移路线怎么选:平迁、改造、重构
从实现手段看,Oracle数据库迁到KingbaseES基本就三条路。到底选哪条,不取决于技术人员的偏好,而取决于系统的现状和可投入的资源。
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 平迁 | 依靠迁移工具自动转换表结构、索引、常用SQL,应用改动量最少 | 业务逻辑简单、SQL写法规范、很少用Oracle特殊语法 |
| 改造 | 工具转换结果只当底稿,对存储过程、函数、特殊SQL做人工改写 | 大多数OLTP业务系统,本次项目采用的就是这条路线 |
| 重构 | 重新设计数据模型、接口协议和应用架构 | 系统耦合度高、SQL大量依赖Oracle专属特性、本来就有重构计划 |
有些人可能会觉得重构一步到位最干净,但现实是重构周期长、风险大,一个跑了几年的业务系统全量重构,回归测试和业务验证的成本会高出几个量级。所以除非系统本身已经在迭代换新,否则尽量选“改造”,用最小的改动换来迁移目标,这才是平滑迁移的意义。
注意:迁移策略一定要在早期定下来,不要边干边改。我见过一个项目因为策略反复摇摆,工具转了一半,手工改了一半,最后两边对不上,工作量翻倍。
2. 对象盘点、兼容性评估与环境准备
2.1 迁移前必须先把Oracle库的家底摸清
迁移的第一件事不是建库,而是盘点。很多系统跑了好几年,DBA换了几轮,库里到底有哪些表、哪些存储过程还在用、哪些对象已经废弃,可能没人说得清。盘点的办法很简单,直接查数据字典,把所有对象按类型统计一遍:
select object_type, count(*) from dba_objects where owner = 'APPUSER' group by object_type order by count(*) desc;这个SQL能让你快速知道总量有多大、哪些类型是核心。但光看数量还不够,还要看依赖关系。建议把dba_dependencies里的依赖关系导出成树状图,存储过程之间的调用链、视图引用哪些表、触发器挂在哪个表上,迁移顺序就靠它来排。
我当时盘点出来的对象清单大概是这样:
| 对象类型 | 数量 | 处理方式 |
|---|---|---|
| 表 | 186 | 工具转换+人工核查 |
| 普通索引 | 342 | 工具转换 |
| 主键/唯一约束 | 98 | 工具转换 |
| 视图 | 27 | 工具转换+人工review |
| 存储过程 | 143 | 人工改写+代码评审 |
| 函数 | 31 | 人工改写 |
| 触发器 | 16 | 人工改写 |
| 序列 | 52 | 工具转换 |
从这个表就能看出来:表、索引、约束这类结构对象基本可以交给工具,压力不大;真正的工作量集中在存储过程、函数、触发器这类带逻辑的对象上。如果盘点阶段发现某个对象的调用方已经不存在,果断归档,不要迁移,省下的改造工作量很可观。
2.2 兼容性差距评估:把对象分成高、中、低风险
盘点完数量,第二步是评估兼容性风险。不是所有对象迁移难度都一样,可以分成三个等级:
- 低风险:普通表、字段、主键、普通索引、序列、同义词,这类对象迁移工具转换率很高,基本是白送的。
- 中风险:外键约束、触发器、视图、分区表、物化视图,转换后需要人工检查边界行为和刷新逻辑。
- 高风险:PL/SQL包、动态SQL、系统包调用、自治事务、回调接口,基本要逐段人工改写。
举个例子,Oracle的分区表有范围、列表、哈希、复合分区多种策略,KingbaseES在兼容模式下支持主流的分区类型,但分区表达式、边界值的写法跟Oracle不完全一样,工具转出来后最好手工核对一遍每个分区的边界,防止数据落入错误分区。物化视图也是一样,Oracle的刷新方式分为fast、complete、force,KingbaseES的刷新机制和触发时机都有差异,必须用真实数据做一轮刷新测试。
评估期间我还顺手统计了应用SQL里使用频率最高的Oracle特性,排在前面的基本就是NVL、SYSDATE、ROWNUM、DECODE、TO_DATE、MERGE INTO、CONNECT BY这几种。这几个正是迁移问题的高发区,后面第4部分会逐个展开讲。
2.3 迁移工具选型与三套环境的规划
KingbaseES官方提供了一整套迁移套件KDMS(金仓数据迁移同步工具),支持对象转换和数据搬移。工具确实能省大量体力活,但我的定位是它只负责“生成第一版可用的脚本”,而不是“一键迁移神器”。工具转换出来的对象脚本必须经过人工review,尤其要检查自动加引号、大小写、隐式类型转换这些容易出偏差的地方。
环境规划上,建议至少搭三套相互隔离的环境:
- 迁移开发环境:放源Oracle库的克隆和目标KingbaseES库,日常做转换和试迁,数据脏一点没关系。
- 应用回归环境:部署整套应用,跑自动化测试和批处理任务,专门用来暴露SQL兼容性问题。
- 准生产演练环境:数据规模和网络配置尽量贴近生产,用来做正式切换前的全流程演练。
这里有一条实操心得:迁移开发环境和应用回归环境千万不要合并。如果合在一起用,开发环境里的临时表、测试数据会影响回归结果,而且权限、日志、连接数也会互相干扰,到时候出了问题都说不清是自己转换的锅还是应用代码的锅,排查效率极低。
3. 结构迁移与数据搬迁实操
3.1 建表语句转换:五个必须手工处理的细节
KingbaseES的Oracle兼容模式对建表语句支持度不错,但下面这几个细节,迁移工具经常处理不到位,需要人工干预。
第一,表空间和存储子句。Oracle建表语句里的TABLESPACE、STORAGE(INITIAL、NEXT这类参数)在KingbaseES里没有意义,转换后直接删掉,让表使用默认表空间。
第二,NUMBER类型的处理。Oracle里NUMBER(10,2)这种带精度定义的,直接转成NUMERIC(10,2)没问题;但无精度NUMBER很危险,工具容易把它转成INT或BIGINT,万一数据里有小数就直接丢精度。我们的策略是:无精度NUMBER一律转成NUMERIC,牺牲一点存储空间,换取绝对安全。
第三,VARCHAR2长度语义差异。Oracle的VARCHAR2(20)默认表示20字节(具体取决于数据库参数NLS_LENGTH_SEMANTICS),而KingbaseES的VARCHAR(20)默认按字符计算。中文场景下差距很大,一个中文字符在UTF-8编码下占3个字节。如果源库是VARCHAR2(30 CHAR),目标库直接写成VARCHAR(30)就会导致长度不够;反过来,如果源库是VARCHAR2(30 BYTE),写成VARCHAR(30)反而变宽松了。正确做法是按字符语义统一,必要时在目标库用VARCHAR(30 CHAR)这种显式写法。
第四,默认值。Oracle表字段默认值经常写SYSDATE,KingbaseES兼容模式下也支持SYSDATE,但有些工具会把它转换成CURRENT_TIMESTAMP,两者在事务内的取值行为略有差异。为了不让业务语义变化,建议保留SYSDATE写法。
第五,字段注释。COMMENT ON语法在KingbaseES里可用,但工具转换时偶尔会丢注释。建议脚本转换后再补跑一次注释生成脚本,方便后续开发和运维查数。
示例转换如下:
-- Oracle原始语句 CREATE TABLE ORDER_INFO ( ORDER_ID NUMBER(18,0) NOT NULL, ORDER_NO VARCHAR2(32 CHAR) NOT NULL, AMOUNT NUMBER(12,2), STATUS VARCHAR2(2), CREATE_TIME DATE DEFAULT SYSDATE, CONSTRAINT PK_ORDER_INFO PRIMARY KEY (ORDER_ID) ) TABLESPACE APP_DATA STORAGE (INITIAL 64K NEXT 64K);-- KingbaseES目标语句 CREATE TABLE ORDER_INFO ( ORDER_ID NUMERIC(18,0) NOT NULL, ORDER_NO VARCHAR(32) NOT NULL, AMOUNT NUMERIC(12,2), STATUS VARCHAR(2), CREATE_TIME TIMESTAMP DEFAULT SYSDATE, CONSTRAINT PK_ORDER_INFO PRIMARY KEY (ORDER_ID) );3.2 数据迁移:分片导入策略与一致性校验
数据搬移听起来就是导出导入,但生产环境的数据量往往很大,几十亿行的表不可能一把梭。这次我们先用KDMS做基础迁移,同时针对大表做了自定义分片。
分片原则是找大表上一个稳定的主键或唯一字段,按区间切段。比如订单表按ORDER_ID范围每100万行一个分片,分批导入。分片的好处有三个:单批失败影响面小、重跑成本低;可以控制对源库的查询负载,不至于把生产库拖垮;便于边导边验证,早发现问题早解决。
每批导完之后,立刻做基础校验:
-- 源库 select count(*) as src_count, count(distinct ORDER_ID) as src_distinct from ORDER_INFO@src_link; -- 目标库 select count(*) as dst_count, count(distinct ORDER_ID) as dst_distinct from ORDER_INFO;只有行数、去重后数量对得上,才继续下一批。全部导完之后,再做字段级抽查比对。我习惯用MD5做逐行checksum:把一行关键字段拼成一个字符串,算MD5,源库和目标库分别聚合,总数和哈希值都相等,才算数据一致。这种校验比单纯看count更能发现脏数据或半截写入。
提醒:如果源库在线还有写入,迁移期间必须开启增量同步,或者至少用一致性快照隔离,不然你刚校验完它又变了,永远对不上。我们当时就是先全量迁移,再追增量,切换前最终只差最后几分钟的变更。
3.3 索引与约束的迁移顺序
索引和约束的迁移不能照搬Oracle的顺序,一个重要经验是先导数据,后建索引和约束。常见错误是先把所有索引、约束全建好再导数据,几千万行的表在导入时每笔插入都要维护索引,速度会慢很多。
我们用的顺序是:
- 先建表结构,不建索引和约束。
- 按分片导入数据,导入期间关闭日志、降低约束开销。
- 数据校验通过后,再批量创建主键、唯一约束和普通索引。
- 最后创建外键约束和触发器,激活完整业务逻辑。
数据量大的表创建索引时,可以用并行创建:
CREATE INDEX IDX_ORDER_CREATE_TIME ON ORDER_INFO(CREATE_TIME) PARALLEL 8;并行度要按CPU核数和磁盘IO能力调节,并行太高会打满同环境其他业务,太低又起不到加速效果。建议先在演练环境压一遍,找到这台机器对应的合理并行度。
4. 兼容性差异与SQL改动实操
4.1 数据类型映射表与边界行为
下面这张映射表是这次迁移实际用到的,可以直接当转换参考:
| Oracle | KingbaseES(推荐) | 说明 |
|---|---|---|
| VARCHAR2(n) | VARCHAR(n) | 注意字符/字节语义,建议统一按字符 |
| NUMBER(p,s) | NUMERIC(p,s) | 精度必须保留 |
| NUMBER(无精度) | NUMERIC | 避免溢出或丢小数 |
| DATE | TIMESTAMP | 保留时分秒语义 |
| TIMESTAMP | TIMESTAMP | 兼容 |
| CLOB | TEXT | 大文本 |
| BLOB | BYTEA | 二进制 |
| RAW(n) | BYTEA | 二进制 |
| CHAR(n) | CHAR(n) | 注意空格填充行为 |
| ROWID | 不直接映射 | 业务逻辑不允许依赖Oracle ROWID |
字符集这块要单独提一句。Oracle源库如果是AL32UTF8,KingbaseES目标库要配成UTF8,这个一般不会出问题;真正容易出问题的是应用连接串里的编码参数。连接参数没指定字符编码时,中文写入在旧库正常、新库乱码,排查起来很费劲。后来统一要求连接串加characterEncoding=UTF-8,并把目标库的编码参数也显式设为UTF8,问题才根治。
4.2 高频SQL语法差异与改写示例
接下来看几个高频差异点,都是实际项目中反复遇到的。
分页:ROWNUM换成LIMIT更稳
Oracle经典分页写法里ROWNUM虽然KingbaseES兼容模式下也能用,但可读性差,执行计划偶尔不稳定,建议统一改写成LIMIT/OFFSET:
-- Oracle SELECT * FROM ( SELECT t.*, ROWNUM rn FROM (SELECT * FROM ORDER_INFO ORDER BY CREATE_TIME DESC) t WHERE ROWNUM <= 20 ) WHERE rn > 10; -- KingbaseES SELECT * FROM ORDER_INFO ORDER BY CREATE_TIME DESC LIMIT 10 OFFSET 10;空字符串与NULL
Oracle里空字符串直接等于NULL,写WHERE status = ''会查不到任何行。KingbaseES兼容模式下大部分行为会向Oracle靠拢,但并不是所有表达式都完全一致。为了保险,代码里统一用IS NULL或NVL显式处理空值,不要依赖空字符串这种隐式语义。
INSERT ALL改多条INSERT
Oracle的INSERT ALL语法在KingbaseES里不支持,需要逐条改:
-- Oracle INSERT ALL INTO ORDER_HIS (ID, SRC) VALUES (ID, 'A') INTO ORDER_HIS (ID, SRC) VALUES (ID, 'B') SELECT ID FROM TMP_ORDER; -- KingbaseES改写 INSERT INTO ORDER_HIS (ID, SRC) SELECT ID, 'A' FROM TMP_ORDER; INSERT INTO ORDER_HIS (ID, SRC) SELECT ID, 'B' FROM TMP_ORDER;CONNECT BY层级查询
存储过程里有一批用CONNECT BY做树形查询的逻辑。KingbaseES兼容模式下支持CONNECT BY,但个别复杂写法会报错,尤其是START WITH子句里带关联子查询的场景。碰到这种我直接改写成递归CTE(WITH RECURSIVE),两种写法都能实现树形查询,递归CTE更通用,也不容易踩兼容性坑。
4.3 存储过程与PL/SQL包适配
存储过程迁移是这次迁移里消耗时间最多的一块,远超普通SQL。KingbaseES兼容模式尽可能兼容PL/SQL,但几类差异还是躲不掉:
- 包(PACKAGE):KingbaseES在兼容模式下支持package,但Oracle内置系统包(比如DBMS_SCHEDULER、DBMS_STATS)的功能覆盖不完全,迁移前要把代码里用到的包和函数列清单,逐个确认替代方案。
- 动态SQL:EXECUTE IMMEDIATE兼容性较好,但USING子句的支持没有Oracle那么完备。遇到绑定变量较多的情况,建议先简化拼接语句,再逐条测试,不要一上来就照搬长SQL。
- 异常处理:PL/SQL异常语法和WHEN OTHERS分支基本兼容,但SQLCODE和SQLERRM返回的文本信息不完全一致。如果应用层有解析异常文本的逻辑,建议改成以错误码为判断依据,减少对措辞的依赖。
- 游标属性:%FOUND、%NOTFOUND在兼容模式下可用,但循环大批量游标时KingbaseES更推荐用FOR循环,性能差异在上万行之后就很明显。
- 自治事务:PRAGMA AUTONOMOUS_TRANSACTION可用,但只能在顶层存储过程里直接调用,嵌套层级多了偶尔会报不支持的特性,迁移前最好把存储过程的调用层级理清楚。
给个经验值:一个100多个存储过程的系统,纯SQL部分大约2~3周能转换完;PL/SQL逻辑复杂的,同样数量可能要6周以上,这还没算回归测试。排期时别太乐观,宁可多留两周缓冲,也不要在上线前赶工。
5. 应用侧适配与连接改造
5.1 JDBC驱动替换与连接串调整
应用从Oracle迁到KingbaseES,第一件事就是换驱动和连接串。KingbaseES提供JDBC驱动,Maven依赖大致这样:
<dependency> <groupId>com.kingbase8</groupId> <artifactId>kingbase8</artifactId> <version>8.6.0</version> </dependency>连接串示例:
jdbc:kingbase8://127.0.0.1:54321/appdb?useUnicode=true&characterEncoding=UTF-8&stringtype=unspecified有几个细节必须注意。端口不是Oracle的1521,KingbaseES默认是54321,具体以部署配置为准。数据库名要跟业务库名对应,不是习惯里的Oracle SERVICE_NAME。连接参数stringtype=unspecified在部分场景可以减少类型不匹配导致的报错,但也可能引入隐式转换风险,建议只在确认需要时开启,不要无脑复制。
连接池也要跟着改。原来用的Oracle数据源要换成通用连接池,驱动类名替换,校验SQL从Oracle的SELECT 1 FROM DUAL改成SELECT 1,减少无谓的数据库往返。连接池的初始连接数和最大连接数先保持与Oracle环境一致,等切换后观察连接占用情况再微调。
5.2 应用层SQL审查与ORM适配对比
驱动换了只是第一步,真正的麻烦在应用代码里写着的SQL语句。我们的做法是把应用所有SQL抓出来做静态审查,重点看两类。
第一类是MyBatis Mapper里的SQL标签。动态SQL里的Oracle函数(NVL、DECODE、SYSDATE)要提前替换,同时检查分页插件生成逻辑,如果用了Oracle分页语法,要改成KingbaseES或PG方言。第二类是Java代码里拼接的SQL字符串,包含ROWNUM、LEVEL、CONNECT BY、MINUS这类Oracle风格语法的都要手动改。
如果是JPA/Hibernate体系,还有方言问题。Hibernate里要指定KingbaseES方言,之前用Oracle方言生成的分页SQL、序列取值SQL都会跟着变,不提前替换,切换当天应用一启动就会报方言错误。
MyBatis还有一个小坑:resultType映射为boolean时,KingbaseES兼容模式下从NUMERIC(1,0)转boolean可能报错。建议在SQL里显式CAST(status AS BOOLEAN),或者干脆返回数字0/1,由应用层自己转换,别依赖ORM的自动映射。
6. 切换演练、性能验证与运维保障
6.1 正式切换流程怎么设计才稳
切换当天最怕的不是慢,是乱。流程必须提前写成操作手册,每个动作落到纸面上,对应执行人和验证命令都写清楚。我们按7步走:
| 步骤 | 动作 | 验证方式 |
|---|---|---|
| 1 | 停止业务写入,应用进入只读或停机维护页 | 观察源库活跃事务归零 |
| 2 | 追平最后增量,停增量同步任务 | 源目标两库最新数据时间点一致 |
| 3 | 做最终数据一致性检查 | count+checksum全表跑一遍 |
| 4 | 切换连接串和负载均衡到KingbaseES | 应用日志出现新库连接记录 |
| 5 | 启动应用,执行冒烟测试用例 | 核心接口全部通过 |
| 6 | 观察窗口1~3小时 | 监控SQL错误率、慢查询、连接数 |
| 7 | 确认稳定后,Oracle保留只读环境作为回退备份 | 不急着释放资源 |
这里强烈建议安排一个“总指挥”,切换过程中的所有指令由他统一发出和确认。执行人不要自行启动或回退任何步骤,宁可多等30秒也不要抢跑。很多时候切换失败不是技术问题,而是多人并行操作后失去控制导致的连锁反应。
6.2 性能对照与调优:从慢查询倒查参数
切换后第一轮性能验证,发现几个原本在Oracle里毫秒级的查询,在KingbaseES上变成了秒级。遇到这类问题不要一上来就怀疑数据库不行,先看执行计划。
KingbaseES里看执行计划用EXPLAIN ANALYZE:
EXPLAIN (ANALYZE, BUFFERS) SELECT ... FROM ORDER_INFO o JOIN CUSTOMER c ON o.CUSTOMER_ID = c.CUSTOMER_ID WHERE o.STATUS = 'N';常见问题有三类。一是统计信息缺失,大表迁移后忘了执行ANALYZE,优化器对行数估计不准,选错执行计划。二是work_mem设置太小,排序和哈希关联走了磁盘临时文件,性能断崖式下跌。三是某些Oracle写法的SQL在KingbaseES里生成的执行计划比预期差,比如函数索引没建,或者字段类型隐式转换导致索引失效。
参数调整的参考方向是这么判断的:
- shared_buffers:对应Oracle里SGA的buffer cache,一般建议设为物理内存的20%~25%,其余留给操作系统cache。
- work_mem:单次排序、哈希操作可用的内存,初始可以给16MB~32MB,但它是per-operation的,并发高时不能给太大,否则内存会爆。
- effective_cache_size:告诉优化器系统文件缓存大概多大,建议设为物理内存的50%~75%,能让关联查询的选择更合理。
- maintenance_work_mem:建索引、VACUUM时使用,建议给到128MB以上,维护操作会明显变快。
每次改完参数,重新加载配置后再EXPLAIN验证。性能问题要和开发一起看,有时候一条SQL的逻辑改写,比调十个参数都管用。
6.3 上线后的备份、监控与维护习惯调整
KingbaseES的数据维护习惯和Oracle差异很大。最典型的是垃圾回收机制,它和PG一样基于MVCC多版本机制,更新删除的旧版本数据需要由autovacuum进程回收。如果autovacuum关闭或者清理不及时,表会膨胀,扫描IO暴涨,查询会越来越慢。
上线前要确认这些:autovacuum打开,大表单独设置回收阈值;定期执行ANALYZE更新统计信息;备份用sys_dump做逻辑备份,同时配合物理备份实现时间点恢复。
监控方面,至少要看四类指标:连接数、慢SQL、临时文件IO、复制延迟(如果做了主备)。连接数超过80%就要告警,出现超过5秒的慢SQL就要拉日志分析,临时文件持续增长说明work_mem可能不够,复制延迟过高说明主库压力大或网络有问题。
备份恢复演练一定要做。迁完之后千万不要只把备份脚本挂上就完事,找一台机器做一次实际恢复演练。等到数据库故障那天才第一次恢复,没验证过备份可用性,那才叫真正的噩梦。
7. 常见问题与排查技巧实录
7.1 高频报错速查表
拿这次迁移遇到的高频问题做了一张速查表,遇到同类报错可以直接对号入座:
| 现象/报错 | 原因 | 处理建议 |
|---|---|---|
| ORA-00933: SQL command not properly ended | 工具转换后残留Oracle独有语法 | 定位到SQL关键字,替换为KingbaseES等价写法 |
| ERROR: syntax error at or near "LEVEL" | 层级查询CONNECT BY不兼容 | 改为WITH RECURSIVE递归CTE |
| ERROR: function nvl(character varying) does not exist | Oracle函数未在兼容模式启用 | 确认实例是否选择Oracle兼容模式,或改写为COALESCE |
| invalid reference to OLD/NEW | 触发器变量名差异 | 检查触发器里:OLD/:NEW写法和触发时机 |
| ERROR: value too long for type character varying(n) | VARCHAR2(n)按字节、VARCHAR(n)按字符导致长度不够 | 按真实最大字节数调整目标列长度 |
| FATAL: sorry, too many clients already | 应用连接数超过max_connections | 增大max_connections,同时核对应用连接池上限 |
| Could not parse "..." as query in JDBC | JDBC驱动版本与应用不匹配 | 升级驱动或检查连接串参数 |
7.2 排错思路与实用小脚本
遇到工具转换后SQL报错,我的排查顺序是固定的:
- 把报错SQL原样复制到数据库客户端执行,确认报错能稳定复现。
- 逐层去掉子查询和条件,缩小范围到出错的语法片段。
- 查这个片段是否用了Oracle特有函数、系统包或关键字。
- 用KingbaseES等价语法改写,先在测试库验证结果集是否一致。
- 改写后再对比前后执行计划,确认性能没有退化。
再分享一个小脚本:批量对比两张表关键字段的校验和。用标准SQL就能实现,不需要额外工具。
SELECT COUNT(*) AS row_count, SUM(ORD_MD5) AS total_md5 FROM ( SELECT MD5( COALESCE(CAST(ORDER_ID AS VARCHAR), '') || '|' || COALESCE(ORDER_NO, '') || '|' || COALESCE(CAST(CREATE_TIME AS VARCHAR), '') ) AS ORD_MD5 FROM ORDER_INFO ) t;源库和目标库分别执行,把统计值对比。这个方法在千万行级表上也能直接跑,比对速度取决于CPU,性能一般可以接受。
数据库迁移不是一次“搬家”,更像一次“心脏手术”:术前体检查对象,术中用流程控风险,术后长期观察恢复状况。做完这次迁移,我的体会是,所谓平滑迁移,不是技术上完全没有波澜,而是你在问题发生之前就已经预演过一遍,出了状况知道往哪里查、怎么回退。只要把兼容性评估做扎实、把切换和回退流程演练到位,从Oracle迁到KingbaseES的大多数项目是能在可控范围内完成的。如果你正好也在做类似的事情,希望这篇实践复盘能给你一些参考,少踩几个我们踩过的坑。