简介国产化替代进程中数据库迁移与适配是不可回避的环节。针对人大金仓KingbaseES数据库这份资源面向Java开发工程师和数据库运维人员提供了一套可直接参考的适配文件集合可帮助解决应用从原有数据库迁移至人大金仓时的建表、初始化以及兼容性调整问题。包体共4个文件整体约242.67MB主要包含zip压缩包、SQL脚本与txt说明文档SQL脚本覆盖常见的建表及数据迁移语句便于在人大金仓环境下执行验证zip压缩包内为配套程序或依赖文件可作为项目改造的素材txt说明文档对资源构成与适配步骤作了必要讲解。目前已有118人学习下载适合正在开展信创项目、需要快速完成数据库底座的团队或个人通过对照SQL脚本与说明文档可以较快梳理出人大金仓与常见数据库在语法和配置上的差异减少逐行修改语句的排查成本为后续Java业务正常对接国产数据库提供基础支撑。1. 适配金仓文件到底在适配什么一次迁移卡壳后的复盘假设你刚从旧系统导出一批 CSV 和 SQL 脚本要灌进金仓数据库应用连上去一查询就报错表不存在、字段类型对不上、中文全是问号。这不是个例。适配国产化金仓文件核心不是把文件拷贝过去而是让文件里的表结构、字段类型、编码和加载方式全部按金仓的规则重来一遍。这篇文章按“连接环境→文件整理→COPY 装载→踩坑排查→对账验证”的顺序把整条路走通。适合手里正拿着旧库文件、准备做国产化改造的研发或运维看完可以直接照步骤操作。2. 文件适配前先把环境跑通驱动选择、建库与最小连接脚本2.1 驱动选型先决定走 PG 还是 Oracle 兼容模式金仓数据库的一个常见特点是一套内核对外提供两种兼容模式一种行为接近 PostgreSQL一种行为接近 Oracle。这个选择会直接影响你后面写的每一句 SQL。做文件适配的时候我通常建议优先走 PG 兼容模式尤其是当你手里的源文件是 CSV 或 mysqldump 产物时。选 PG 模式有三个实际好处第一生态里的 psycopg2、psql 这类工具能直接连上不用额外装一堆依赖第二COPY 命令的语法和 PostgreSQL 基本一致文件装载路径最短第三网上大量关于 PostgreSQL 的排错经验可以直接套用。如果你接手的实例已经初始化成了 Oracle 模式也不用急着重建库后面写 SQL 时注意 NVL、字符串拼接、自增列这些差异就行只不过文件装载的效率通常会低一些。对比项PG 兼容模式Oracle 兼容模式连接方式和开源生态工具兼容简单直接需要留意驱动和会话参数差异COPY 装载语法与 PostgreSQL 一致效率高部分版本需要绕道效率略低建表语法serial / 显式序列都能用自增列写法有差异适用文件CSV、pg_dump、mysqldumpOracle 导出的 SQL、ctl 文件选择依据很简单你的源文件来自哪边就优先选哪边的兼容模式。这一步不决定最终能不能成但决定后面是顺利还是处处卡壳。2.2 建库建用户两个模式的 DDL 差异环境到位之后第一件事是建一个独立的迁移库。强烈建议不要直接往业务库灌数据文件适配过程中会反复 TRUNCATE、重建表独立库能让你放开手脚试错。建库建用户的语法在金仓里跟原生的 PostgreSQL 略有区别主要看当前实例是什么兼容模式。-- PostgreSQL 兼容模式 CREATE USER mig_user PASSWORD Change_Me_2024; CREATE DATABASE migdb OWNER mig_user ENCODING UTF8; -- Oracle 兼容模式 CREATE USER mig_user IDENTIFIED BY Change_Me_2024; CREATE DATABASE migdb OWNER mig_user ENCODING UTF8;上面第一段是 PG 模式的写法第二段是 Oracle 模式的写法。注意 Oracle 模式下字符串用双引号包密码PG 模式下用单引号写反了会报语法错误。创建数据库时指定 ENCODING UTF8 非常重要它决定了后续所有文件的编码基线。如果你的源文件是 GBK我建议保留为 UTF8 库在装载时做编码转换而不是把整个库改成 GBK后面程序连接、报表输出时到处都要考虑编码容易漏。2.3 最小连接脚本确认库能通再往下走环境建好后先用最小脚本验证一次连接避免文件整理完才发现连接串有问题。我用 Python 写的这个脚本十行左右能同时确认驱动、连接串、schema 可见性三个关键点。import psycopg2 conn psycopg2.connect( host127.0.0.1, port54321, dbnamemigdb, usermig_user, passwordChange_Me_2024, options-c search_pathpublic,app_schema ) cur conn.cursor() cur.execute(select version()) print(cur.fetchone()[0]) cur.close() conn.close()options参数里的search_path很关键。金仓和 PostgreSQL 一样schema 决定了你在不写库名前缀时默认去哪个模式里找表。文件适配最常遇到的翻车现场就是建表建到了 A schema程序用默认用户连上去之后去 B schema 查报表不存在。这里把search_path显式设置好能提前消掉一类问题。port填你实际实例的端口不要照抄很多金仓环境默认端口和 PostgreSQL 并不一样以你的部署配置为准。3. 把源文件装进金仓从 dump 改造到 COPY 快速装载3.1 先看源文件三种形态的处理节奏我拿到一批文件时不会先急着找工具导入而是先按文件形态分个类不同形态的处理节奏完全不同。第一种是 CSV 或固定分隔符的文本导出文件这种最省心整理表结构后直接 COPY 就能进库。第二种是 mysqldump 或 pg_dump 这类 SQL 脚本文件里面混着建表语句、INSERT 语句和各类设置项需要先把语法改造一遍。第三种是 Oracle 风格的控制文件加数据文件通常还带日期格式的坑处理起来最费劲。文件形态处理重点推荐工具CSV / 文本导出字段顺序、空值、编码COPYmysqldump 脚本反引号、引擎、自增列sed 手工改 DDLOracle 导出文件日期格式、NVL、控制文件转换脚本 COPY确定好文件形态之后表结构还优先于数据文件处理。我的习惯是先把所有表建好再开始导数据。如果先导数据后改表结构字段类型不匹配导致的报错会让你反复重导浪费时间。3.2 用 COPY 装载 CSV 文件命令与参数数据装载阶段COPY 是金仓里效率最高的文件导入方式。它比一条条 INSERT 快一个数量级适合 GB 级别的文件。下面这条是最常见的 CSV 装载命令在 psql 里执行。\copy public.t_user(id, name, created_at) FROM /data/export/t_user.csv WITH (FORMAT csv, DELIMITER ,, NULL NULL, HEADER true, ENCODING UTF8)\copy是在客户端执行的 COPY文件路径指向你本机目录普通用户就能用不需要超级用户权限。如果改成COPY去掉反斜杠则是在数据库服务端执行文件必须放在数据库服务器上而且通常需要更高级别的权限。文件适配的场景里数据文件往往在应用服务器上我一般直接用\copy省去传文件的步骤。参数解释一下FORMAT csv表示按 CSV 规则解析字段内含逗号、引号的情况会自动处理DELIMITER ,是列分隔符如果源文件用的是制表符改成DELIMITER E\tNULL NULL告诉数据库把文件里的字符串 NULL 当作 SQL 的 NULL而不是往字段里塞字符串HEADER true跳过第一行标题ENCODING UTF8要与文件实际编码一致。提示文件里字段顺序和表字段顺序不一致时必须在表名后面把字段列出来顺序和文件列顺序一致例如t_user(id, name, created_at)。不列字段直接写表名COPY 会按表结构顺序取文件列对不上的后果是数据错位这种错误很难一眼看出来。3.3 mysqldump 文件改造成金仓结构最小套路如果手里的是 mysqldump 导出的 SQL 文件不能直接喂给金仓里面大量 MySQL 专属语法会让解析器直接罢工。对于小规模项目我用 sed 处理掉最明显的几类差异再手工把建表语句过一遍。sed -e s///g \ -e s/ENGINEInnoDB DEFAULT CHARSETutf8mb4//g \ -e s/ AUTO_INCREMENT//g \ dump.sql dump_kingbase.sql这里做了三件事去掉反引号MySQL 用反引号包标识符金仓不需要去掉表尾的存储引擎和字符集声明去掉AUTO_INCREMENT关键字。处理完之后的建表语句已经能进金仓但还差一步——自增主键。MySQL 里id INT AUTO_INCREMENT PRIMARY KEY拿到金仓不能直接用常见做法是拆成序列加默认值。CREATE TABLE public.t_user ( id bigint DEFAULT nextval(seq_t_user_id) PRIMARY KEY, name varchar(64), created_at timestamp NOT NULL DEFAULT now() ); CREATE SEQUENCE seq_t_user_id START WITH 1;为什么不用 serial 类型金仓的 serial 在部分兼容模式下表现不一致而且后续重置序列时显式序列更好控制。把序列单独建出来的最大好处是数据灌进去之后你可以用一句setval把序列拨到当前最大 id避免后续应用写入时撞主键。这个细节会在下一章的避坑清单里详细展开。4. 适配金仓文件的避坑清单五个高频翻车点与排查路径4.1 表名大小写导致 relation “T_USER” does not exist现象建表时写的是T_USER程序查询时也写T_USER但报错 relation T_USER does not exist。去数据库里 \d 看表表名显示成小写t_user。原因这是从 PostgreSQL 沿袭下来的行为——不带引号的标识符会被自动折叠成小写。建表时写T_USER和写t_user是同一个表但你在程序里如果用了带引号的写法比如T_USER就会严格区分大小写反而找不到表。解决统一不带引号裸写表名和字段名。如果建表脚本里有人手工给表名加了双引号趁早把引号去掉重建表。程序侧如果用了 ORM也检查一下是否强制了一致的大小写。4.2 COPY 后序列还在 1新插入撞主键现象COPY 导入一万行数据成功应用一插入新记录就报 duplicate key value violates unique constraint主键冲突。打开表看最大 id 已经到一万多但序列值还停在 1。原因COPY 是直接写数据文件不会触发序列自增。序列和表的关联只是“默认值”层面的约定COPY 绕过了这条约定。这几乎是文件导入后必踩的坑尤其是从 MySQL 迁过来的表原来的自增主键在 COPY 之后基本都会出这个问题。解决导入完成后立刻把序列拨到当前最大 id。下面这条 SQL 是惯用写法SELECT setval(seq_t_user_id, (SELECT max(id) FROM public.t_user));执行时把seq_t_user_id换成你自己的序列名。如果同一张表有多个依赖序列的字段每字段都要拨一次。这个操作建议写进你的导入脚本里每次导完自动执行别等到应用报错再补。4.3 中文显示成问号或乱码编码要统一现象CSV 文件用 Excel 打开中文正常COPY 进金仓后部分中文变成问号查询出来也是乱码。文件不大但报错里面有 invalid byte sequence for encoding UTF8。原因文件实际编码是 GBK数据库是 UTF8COPY 按 UTF8 解析时遇到无法映射的字节直接报错或写入替代字符。Excel 另存为的 CSV 特别容易是 GBK这是文件适配里最隐蔽的坑之一。解决装载前用iconv把文件转成 UTF8再执行 COPY。iconv -f GBK -t UTF8 t_user.csv t_user_utf8.csv如果文件里既有中文又有特殊符号转换报错时用-c参数跳过无法转换的字节但要注意这可能会丢数据。更稳妥的做法是确认源系统导出的编码和业务方确认后再转换。判断文件真实编码可以用file -bi t_user.csv看返回的 charset 字段。4.4 导入完成后查询慢统计信息不是玄学现象数据量不算大几万行但关联查询走全表扫描执行计划显示 rows 估算偏差大。导入前同样的 SQL 在旧库是秒回换了金仓变成十几秒。原因COPY 大量数据之后统计信息仍然停留在建表时的空表状态。规划器按零行估算选择了错误的连接方式和访问路径。这不是金仓特有的问题所有基于代价规划的数据库都会这样只是很多人第一次做国产化迁移时容易忽略。解决导入完成之后立即执行一次ANALYZE;让数据库刷新统计信息。如果这还不够用执行计划确认一下EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM public.t_user u JOIN public.t_order o ON u.id o.user_id;看输出里的rows估算和实际行数是否差很远差得远就再把 ANALYZE 做一次。数据量大的表还可以针对关联字段单独ANALYZE public.t_user。4.5 大文件 COPY 到一半失败拆批重导而不是硬扛现象1GB 的 CSV 文件 COPY 到一半报错终止有时候是内存暴涨有时候是连接中断重启再来还是同一个位置附近挂掉。报错信息不统一排错很难受。原因大文件单次 COPY 对服务端内存、临时空间、网络稳定性都有要求任何一个环节抖动都会中断。已经导入的部分在单个事务里会全部回滚等于白跑。解决把大文件拆成小块分批导入。每个文件控制在合理规模比如 20 万行左右一批。拆文件用split命令split -l 200000 t_user_utf8.csv part_然后循环对每个 part 文件执行 COPY。出问题时只需要重导失败的批次不用整表重来。如果拆完发现某个批次反复失败单独查那一批文件有没有异常行通常坏数据就那么几行定位后清理即可。5. 迁移验证与进阶技巧对账脚本和慢 SQL 追踪5.1 三分钟对账count、摘要、抽样文件灌进库之后第一反应不是打开表看几眼而是做一次可复现的对账。对账要有三个层面行数一致、内容一致、边界一致。行数用count(*)对比源和目标内容用摘要值对比边界用最大最小 id 对比。摘要用的 SQL 我习惯这样写SELECT count(*) AS cnt, md5(coalesce(string_agg(t_user.id || | || t_user.name, , ORDER BY t_user.id), )) AS digest FROM public.t_user;源库用同样的写法生成一个摘要两边的cnt和digest一致才算基本对得上。这个写法不适合超大数据量几十万行以内没问题上亿行跑摘要会很吃力这时候改为随机抽样对比抽 1000 条逐字段比对。比对完记得看一眼最大 id 和最小 id防止文件被截断。5.2 让慢 SQL 自己现形EXPLAIN 与 ANALYZE 习惯数据进去了查询也通了不等于任务结束。我把 EXPLAIN 当成文件适配的最后一道工序跑一遍业务方提供的核心查询观察执行计划里的三层东西是不是全表扫描、估算行数和实际行数差多少、有没有排序和临时文件。如果估算严重偏差优先确认统计信息按第 4.4 节跑 ANALYZE。这几年做文件适配我的习惯是把导入脚本和对账脚本放进同一个目录文件名带上批次号跑完自动生成结果文件十分钟后看差异。导入完成后顺手执行一次 ANALYZE再跑一遍对账确认无误才收工。这个习惯救过我很多次希望帮到你。本文还有配套的精品资源点击获取