实话实说,做开发的基本都能感受到,国产数据库替换这件事,已经躲不开。
这几年信创落地持续推进,人大金仓在政务、央国企项目里面出现得越来越多。我身边有位后端开发同事,去年他们单位启动国产化改造,数据库直接要求切换金仓。不是建议评估选型,而是硬性任务,不管愿不愿意,都得落地。我平时工作大多跟MySQL打交道,早晚也得实打实接触这类国产数据库。
目录
一、实验环境与前置准备
1.1 本地硬件与软件版本
1.2 测试库与测试数据准备
1.3 迁移目标
二、金仓KES本地部署与基础环境验证
2.1 安装包获取与图形化安装实操
2.2 数据库实例可视化初始化
2.3 服务状态核验与DBeaver连接环境验证
四、基于KDT工具的迁移兼容性检测
4.1 KDT工具新建评估任务
4.2 扫描结果分类排查
五、数据库结构适配 + 自定义兼容改造
5.1 字段类型手动适配改造
5.2 自定义兼容函数实现
六、全量数据迁移 + 数据一致性校验
6.1 结构与数据分步迁移
6.2 迁移耗时实测
6.3 数据一致性校验
6.4 轻量增量同步模拟
七、业务SQL深度优化实战
7.1 大偏移量深度分页优化
7.2 JSON字段检索性能优化
八、金仓数据库个性化参数调优
8.1 核心配置文件路径
8.2 本地化参数定制调整
8.3 参数生效与性能验证
九、KWR性能报告实操,自主定位数据库瓶颈
9.1 KWR插件开启
9.2 生成性能报告实操
9.3 瓶颈分析与优化
十、极简主备同步高可用测试
10.1 主库配置
10.2 备库克隆与启动
10.3 同步验证
十一、迁移全流程踩坑总结
十二、总结与国产化实践感悟
动手实操之前,我找了不少做后端、运维的同行交流,大家聊起金仓,顾虑基本逃不开三点。第一点就是语法兼容,担心迁移的时候要大面积改写业务SQL,改到头疼;第二点是性能,很多人担心换到国产库之后,一上生产环境就出性能问题;第三点是排错资源,网上现成的故障案例不多,碰到问题只能自己慢慢摸索排查。这些说法听了很多次,但等到真要编写迁移方案、敲定上线时间窗口的时候,每一项都实实在在会卡住进度。
我手头没有企业级测试服务器资源,索性直接拿日常办公用的台式机,完整走完整套迁移流程。从安装部署KES V9,做兼容性扫描,调整不匹配的表结构,完成全量数据迁移再测试增量同步;接着处理业务SQL的性能问题,调试数据库各项参数,分析性能输出报告;最后还搭了一套极简的主备架构。整个过程完全不依赖公司服务器,所有执行命令、程序报错信息、性能统计数据,都是我反复调试跑出来,调试过程的截图也全部保存了下来。
写下这份复盘,一方面是给自己这段实操做一份留存记录。另外我也发现,很多中小团队做数据库国产化,并不缺网上的方案模板,真正稀缺的是普通人在普通电脑上完整跑通后的一手实操经验。文中我尽量还原踩过的各类问题、对应的处理手段,还有每一步大致消耗的时间。个人水平有限,文中如果存在疏漏,欢迎大家指出。
一、实验环境与前置准备
1.1 本地硬件与软件版本
我的测试机器就是日常办公台式机,硬件配置为Intel i5‑12400(6核12线程),内存16G DDR4‑3200,硬盘是512G NVMe固态,操作系统为Windows10专业版22H2。
软件版本尽量对齐真实生产环境常用版本:
源端数据库:MySQL 8.0.36社区版,使用默认端口3306
目标端数据库:人大金仓KingbaseES V9.0.3个人版,端口54321
迁移工具:金仓官方KDT迁移工具V2.3
数据库客户端工具:DBeaver 24.0.1
性能验证手段:直接统计SQL执行耗时,搭配自己写的Python压测脚本
1.2 测试库与测试数据准备
为了贴近真实业务,我自建两张业务核心数据表,在MySQL中预先生成百万级测试数据集。如果使用空库做迁移测试,参考价值很低。
用户表t_user用来保存用户基础信息,包含JSON扩展字段,总共有32万条记录。
-- MySQL端建表语句 CREATE TABLE t_user ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID', username VARCHAR(64) NOT NULL COMMENT '用户名', age TINYINT COMMENT '年龄', city VARCHAR(32) COMMENT '所在城市', info JSON COMMENT '扩展信息', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' );订单表t_order存储业务订单数据,覆盖分页读取、时间条件筛选、状态统计这些高频业务场景,一共126万行数据。
-- MySQL端建表语句 CREATE TABLE t_order ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '订单ID', user_id INT NOT NULL COMMENT '用户ID', order_no VARCHAR(32) NOT NULL COMMENT '订单编号', amount DECIMAL(10,2) NOT NULL COMMENT '订单金额', status TINYINT DEFAULT 0 COMMENT '订单状态 0待支付 1已支付 2已完成', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', KEY idx_user_id (user_id), KEY idx_create_time (create_time) );最开始写存储过程批量插入测试数据,没有做分批提交,插入32万条记录足足跑了接近10分钟。调整为每1000行做一次事务提交之后,写入速度直接提升三倍。
数据生成完成后做核对:t_user一共320000行,t_order共1260000行,JSON、时间、数值字段全部填充随机测试值,覆盖业务中经常碰到的查询场景。
1.3 迁移目标
做测试之前,我给自己定了三条可以量化的目标,不搞虚的概念。
保证数据不会丢失:迁移之后,数据行数、字段内容、JSON里面的数据要做到100%和源库一致。
尽量少改动原有语法:依靠自建兼容函数适配核心业务SQL,尽可能不去修改上层业务代码。
性能不能明显落后原有数据库:核心查询SQL执行耗时要持平甚至优于MySQL,批量写入的性能差距控制在10%以内。
二、金仓KES本地部署与基础环境验证
2.1 安装包获取与图形化安装实操
2.1.1 安装包下载
1. 打开人大金仓官方网站下载板块,找到【数据库‑KES‑V9R1C10】,下载Windows平台X64版本,文件格式为ISO镜像,文件大小3.4G。
2. Windows10、Windows11可以直接双击挂载这个ISO镜像。旧版本Windows系统,需要解压软件把里面exe安装程序提取出来。
3. 存放安装包的文件夹路径全部使用英文,千万不要出现中文、空格以及特殊符号。
2.1.2 标准化安装步骤
1. 权限处理:右键Setup‑KingbaseES‑V9‑Windows‑x64.exe,选择以管理员身份运行,弹窗里选定简体中文,进入安装向导。
2. 许可协议勾选同意,继续下一步。
3. 安装类型这里我直接选完全安装。该选项会完整安装数据库内核、可视化管理客户端、JDBC驱动、迁移工具、各类命令行组件,适合本地学习调试。精简或者典型安装会缺失驱动与配套工具,不建议选择。
4. 设置安装路径,自定义路径填写D:\Kingbase\ES\V9。千万不要使用类似D:\国产数据库、D:\Kingbase ES这类带中文、空格的路径,后续实例初始化会直接报错。
5. 确认快捷方式路径保持默认,点击开始安装。固态硬盘等待4‑6分钟,如果是机械硬盘,耗时大概7‑9分钟,等待文件复制完毕。安装结束,不要勾选一键初始化实例,直接关闭安装窗口。
2.2 数据库实例可视化初始化
2.2.1 工具入口,两种方式任选其一
通过系统开始菜单,找到人大金仓KingbaseES V9,打开数据库初始化工具。
直接访问安装目录,双击运行
D:\Kingbase\ES\V9\bin\initdb.exe。
2.2.2 初始化分步配置
操作类型选择创建全新数据库实例,实例名称保持默认
KINGBASE,监听端口固定54321,这里我没有修改。设置管理员账号密码。超级管理员账号固定是
system,密码有强制校验规则:长度不能低于8位,同时要包含大写字母、小写字母、数字以及特殊符号。举个合规例子Test@2026,简单纯数字、纯字母密码会直接被拦截,设置完成二次确认密码后点下一步。字符集和兼容模式设置:数据库编码选UTF8,排序规则
zh_CN.UTF‑8;兼容模式务必切换为MySQL模式,能大幅减少后续SQL适配工作量。数据存储目录填写
D:\Kingbase\ES\V9\data,再次确认路径不存在中文或者空格。其余高级参数全部保持默认,点击执行,初始化过程大概需要2分钟。
初始化成功之后,勾选注册成为Windows系统服务,这样数据库就可以开机后台自动启动,点击完成结束配置。
2.3 服务状态核验与DBeaver连接环境验证
2.3.1 服务启停核验
进入目录D:\Kingbase\ES\V9\Server\bin,执行下面命令启动数据库实例:
.\sys_ctl -D "D:\Kingbase\ES\V9\data" start控制台输出「服务器进程已经启动」,再执行状态查看命令:
.\sys_ctl -D "D:\Kingbase\ES\V9\data" status输出内容能够看到PID,就代表实例正常运行,54321端口对外开放。
2.3.2 DBeaver连接配置
直接拿PostgreSQL通用驱动会连接失败,必须使用金仓配套自带JDBC驱动。
1. 新建数据库连接,数据库类型选定KingbaseES。
2. 基础连接参数填写如下:
参数项 | 填写内容 |
主机 | 127.0.0.1 |
端口 | 54321 |
数据库 | test |
用户名 | system |
密码 | 安装时设置的管理员密码 |
3. 将驱动替换为安装目录下面jdbc/kingbase8.jar,测试连接,提示连通正常就完成。
2.3.3 版本与兼容模式核验
打开SQL编辑器,依次执行两条SQL语句查看信息:
--查看版本 select version(); --查看SQL兼容模式 show sql_compatible;判断标准:
版本返回内容里面包含
V009R001C010;sql_compatible输出为mysql。
万一兼容模式不对,执行下面语句修改并且重载配置:
alter system set sql_compatible = 'mysql'; select pg_reload_conf();确认没问题之后,创建业务使用的数据库:
CREATE DATABASE testdb;后续全部业务操作都在testdb库执行,基础部署工作到此结束。
实操避坑汇总
安装目录、数据存放目录,一律禁用中文、空格、特殊符号;
管理员密码必须满足复杂度,大小写、数字、特殊符号缺一不可;
客户端连接不要使用PostgreSQL通用驱动,只能用KES官方JDBC包;
日常调试启停,直接使用start/status/stop命令,不一定非要注册系统服务。
MySQL 至人大金仓 KES 全链路迁移流程图:
四、基于KDT工具的迁移兼容性检测
千万不要拿到迁移工具就直接导入数据。第一步一定要跑兼容性扫描,提前定位待改造点。否则迁移中途抛出报错,回滚返工要耗费不少时间。金仓官方的KDT迁移工具自带兼容性评估,这块功能十分实用。
4.1 KDT工具新建评估任务
打开KDT软件,按下面步骤一步步配置任务:
左上角点新建项目,项目命名
mysql2kes_test,项目保存路径设置为D:\kdt_project,确认创建。左侧菜单栏切换兼容性评估,新建评估任务,任务名填写
testdb_eval。源数据库配置:数据库类型MySQL,驱动文件选中本地
mysql‑connector‑java‑8.0.36.jar;主机127.0.0.1,端口3306,库名test_db,账号root,填入MySQL密码,点击测试连接,连通后继续下一步。目标数据库配置:数据库类型选择人大金仓,驱动选用金仓自带
kingbase8‑9.0.3.jar,地址127.0.0.1,端口54321,数据库testdb,账号system填写对应密码,测试连接成功进入下一步。评估对象勾选
t_user、t_order两张业务表;评估选项全部勾选:语法兼容性、数据类型映射、函数兼容性、分页语法检查、约束兼容性。点击开始评估,等待大概一分钟,就能输出完整扫描报告。
4.2 扫描结果分类排查
评估报告出来,统计结果为高风险12项,中风险37项,低风险21项。我没有一条一条机械修改,而是按影响范围分组处理,优先解决高风险问题。
第一类是函数不兼容,占了绝大多数高风险,合计8处。主要集中在三个MySQL高频函数:IFNULL、SUBSTRING_INDEX、DATE_FORMAT。金仓没有同名原生实现,直接运行SQL就会抛出“函数不存在”报错。
第二类属于分页语法差异,一共2处高风险。MySQL的limit m,n写法虽然在金仓可以跑通,但二者语义存在细微差别,大偏移量分页场景容易出现业务异常,归类为语法高风险。
第三类是字段类型适配,包含2个高风险、28个中风险。举个例子,MySQLtinyint(1),KDT默认映射成smallint,存储没问题,但是业务语义不匹配;JSON类型默认映射普通json文本,没办法建立索引;datetime类型精度、默认值行为也和MySQL有区别。
剩下的低风险大多集中在字符集排序、注释格式,不会阻碍业务运行,可以放到后期再处理。
看完这份评估报告心里就有数,迁移的主要工作量集中在函数兼容、字段适配;分页语法只要统一改写规范,整体迁移难度可控。
五、数据库结构适配 + 自定义兼容改造
表结构适配,是MySQL往人大金仓迁移最重要的前置步骤。必须先把表结构调整完毕,再导入数据。不然数据入库之后,会出现类型错乱、索引失效,还得二次整改修复。
我没有完全依赖KDT工具一键自动转换表结构,而是逐个字段人工梳理适配细节。尽量贴合原有业务SQL的习惯,最大限度减少业务侧代码改动。
5.1 字段类型手动适配改造
我整理两张业务核心表的字段映射对照表,在KDT自动映射结果基础之上做进一步优化,不光要保证语法跑通,同时兼顾存储空间占用、查询性能还有业务语义。
MySQL 字段类型 | KDT 默认映射 | 手动优化映射 | 优化原因 |
TINYINT(1) | SMALLINT | BOOLEAN | 布尔状态语义直观清晰,存储空间占用更小 |
INT | INTEGER | INTEGER | 类型完全兼容,无需改动 |
BIGINT | BIGINT | BIGINT | 类型完全兼容,无需改动 |
VARCHAR(n) | VARCHAR(n) | VARCHAR(n) | 类型完全兼容,无需改动 |
TEXT | TEXT | TEXT | 类型完全兼容,无需改动 |
DATETIME | TIMESTAMP | TIMESTAMP(0) | 精确到秒,匹配业务时间精度,缩减磁盘占用 |
JSON | JSON | JSONB | 二进制存储,支持 GIN 索引,模糊查询、检索性能大幅提升 |
DECIMAL(m,n) | NUMERIC(m,n) | NUMERIC(m,n) | 高精度数值完全兼容,无需改动 |
工具自动生成的建表SQL存在不少冗余,部分类型处理不够理想,两张核心表我全部手写建表语句,手动在库中执行部署。
-- 金仓端用户表 CREATE TABLE t_user ( id SERIAL PRIMARY KEY, username VARCHAR(64) NOT NULL, age SMALLINT, city VARCHAR(32), info JSONB, create_time TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP ); -- 金仓订单表 CREATE TABLE t_order ( id BIGSERIAL PRIMARY KEY, user_id INTEGER NOT NULL, order_no VARCHAR(32) NOT NULL, amount NUMERIC(10,2) NOT NULL, status BOOLEAN DEFAULT false, create_time TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_order_user_id ON t_order(user_id); CREATE INDEX idx_order_create_time ON t_order(create_time);MySQL依靠AUTO_INCREMENT实现主键自增逻辑;人大金仓通过SERIAL、BIGSERIAL绑定序列,二者效果对等。
我前期调试踩过一个坑:迁移完存量数据,直接新增数据会报主键冲突。排查后发现迁移工具不会同步序列的当前数值,序列默认从1开始,但是表里已经存在大量数据。
需要手动调用setval()把序列值对齐表里最大主键,避免主键重复报错。
-- 同步序列当前值为表内已有最大ID,第三个参数true代表下次自增自动+1,杜绝主键重复 SELECT setval('t_user_id_seq', (SELECT MAX(id) FROM t_user), true); SELECT setval('t_order_id_seq', (SELECT MAX(id) FROM t_order), true);5.2 自定义兼容函数实现
为了尽量不动上层业务代码,我选择直接在金仓库内部新建同名兼容函数,业务SQL基本不用修改就可以直接执行。下面是三个高频函数的实现过程。
1. IFNULL 兼容函数
金仓原生自带COALESCE,能力和MySQLIFNULL完全一致,简单封装一层就可以。
CREATE OR REPLACE FUNCTION ifnull(anyelement, anyelement) RETURNS anyelement AS $$ SELECT coalesce($1, $2); $$ LANGUAGE sql IMMUTABLE STRICT;执行完成测试:SELECT ifnull(null, 'test');返回test,输出结果和MySQL保持一致。
2. SUBSTRING_INDEX 兼容函数
这个函数调试耗费的时间最长。金仓原生只有string_to_array用来把字符串切分成数组,需要自己完整实现按分隔符截取,同时要支持正数、负数两种下标。
CREATE OR REPLACE FUNCTION substring_index(str text, delim text, count integer) RETURNS text AS $$ DECLARE arr text[]; arr_len integer; BEGIN -- 空值拦截 IF str IS NULL OR delim IS NULL OR count = 0 THEN RETURN ''; END IF; arr := string_to_array(str, delim); arr_len := array_length(arr, 1); IF count > 0 THEN IF count >= arr_len THEN RETURN str; END IF; RETURN array_to_string(arr[1:count], delim); ELSE IF abs(count) >= arr_len THEN RETURN str; END IF; -- 适配PG数组闭区间切片,精准截取末尾abs(count)段 RETURN array_to_string(arr[arr_len + count + 1 : arr_len], delim); END IF; END; $$ LANGUAGE plpgsql IMMUTABLE STRICT;刚写完第一次做测试,负数参数行为异常。执行SELECT substring_index('a,b,c,d', ',', -1);,预期输出d,实际返回完整字符串a,b,c,d。
我调试了两遍,在代码中加入raise notice打印数组长度以及切片起止位置,定位到负数下标计算公式少加数字1。修正代码之后,正数、负数输入场景全部和MySQL执行结果匹配。
3. DATE_FORMAT 兼容处理
针对DATE_FORMAT,我没有封装自定义函数。金仓内置to_char功能更强,执行性能也更好,业务中这类语句数量不多,直接改写SQL成本可控。
MySQL原有写法:
SELECT DATE_FORMAT(create_time, '%Y-%m-%d') FROM t_user;金仓改写之后写法:
SELECT to_char(create_time, 'YYYY-MM-DD') FROM t_user;表结构、自定义兼容函数全部调整完毕,我重新运行KDT兼容性评估,全部高风险项清零,剩下低风险项不影响业务运行,这时候就可以正式迁移数据。
六、全量数据迁移 + 数据一致性校验
6.1 结构与数据分步迁移
迁移工作拆成两步,先处理表结构相关(索引、约束,表结构我们已经手动建好),再导入全量业务数据。不要一边建表一边大批量插入,容易触发锁等待。
回到KDT工具,新建一份数据迁移任务:
左侧菜单切换数据迁移,新建迁移任务,源端目标端配置沿用兼容性评估任务的参数。
迁移对象勾选
t_user、t_order两张表,核对字段映射关系无误。迁移参数:并发线程设置4。工具默认8线程,在我这台本地机器开启8线程,CPU直接占满,系统卡顿明显;设置4线程,CPU占用稳定在50%上下。批量提交行数设置1000行,避免大事务过度消耗内存。
勾选跳过表结构创建,表结构已经手动优化完成。
点击开始迁移,等待任务跑完。
6.2 迁移耗时实测
我全程盯着任务进度条,得到下面实测结果:
t_user:320000行,耗时28秒,平均每秒写入约11400行
t_order:1260000行,耗时1分42秒,平均每秒写入约12300行
整体耗时2分10秒。百万级数据迁移的速度,比我自己预估的还要快一点。
这里遇到一个故障,最开始直接用默认8线程跑迁移,KDT程序中途闪退,全部任务进度丢失。翻看日志,属于内存溢出。调整线程到4之后,内存占用稳定维持在2G,整个迁移过程十分平稳。
6.3 数据一致性校验
迁移任务显示成功不等于数据没问题,一定要做一致性校验,保证不会出现数据丢失。我一共做了三层校验逻辑。
行数核对:源库目标库分别执行
SELECT COUNT(*) FROM 表名;,两张表行数完全对上,32万、126万行没有一条偏差。随机抽样比对:根据主键随机抽取1000行记录,逐字段对比;JSON字段转为文本形式做比对,全部内容完全匹配。
聚合结果校验:分别统计订单总金额、用户平均年龄这类聚合计算,两边输出结果一模一样。
三层校验全部通过,确认迁移之后数据完整,不存在丢失、截断、乱码现象。
6.4 轻量增量同步模拟
为了模拟生产环境不停机迁移场景,我开启KDT的增量同步功能。底层原理就是读取MySQL binlog日志,把新增、变更数据持续同步到金仓数据库。
配置并不复杂,全量迁移任务结束,点击开启增量同步,设置同步延迟阈值。
我写了一段Python脚本,持续向MySQL每秒插入10条订单记录,连续跑10分钟。实测同步延迟稳定在1.5‑2秒,没有出现丢数据。对于中小型业务,业务低峰期割接完全够用,停机窗口可以压缩到分钟级别。
七、业务SQL深度优化实战
完成迁移仅仅是第一步,性能能不能扛住业务压力,才是能不能切换业务流量的关键。我挑了两个开发当中经常碰到的慢查询场景,针对性调优。所有性能数据全部来自本地实测,不是网上摘抄的通用教程。
测试耗时统计,打开金仓\timing on,每一条SQL重复执行三次,取平均耗时,规避缓存带来的数据干扰。
7.1 大偏移量深度分页优化
现象描述
订单列表分页查询,翻到5000页之后,查询速度会明显下滑。沿用MySQL原来写法的SQL:
SELECT * FROM t_order ORDER BY id LIMIT 20 OFFSET 100000;优化之前执行耗时:1.28秒。
执行计划查看语句:
EXPLAIN ANALYZE SELECT * FROM t_order ORDER BY id LIMIT 20 OFFSET 100000;可以看到会做全表扫描,读取100020行,再丢弃前面100000条记录。偏移数值越大,扫描行数就越多,性能持续变差。
优化思路
采用子查询定位主键,之后回表关联的方案。利用主键索引定位分页起始ID,再读取完整行数据,规避大量扫描。
改写完成SQL:
SELECT t.* FROM t_order t INNER JOIN ( SELECT id FROM t_order ORDER BY id LIMIT 20 OFFSET 100000 ) tmp ON t.id = tmp.id ORDER BY t.id;优化效果
改写之后耗时0.07秒,性能大概提升18倍。执行计划里面内层子查询走主键索引,只扫描索引记录,外层仅仅读取20行业务数据,IO开销下降明显。
我还测试游标分页写法,适合APP端上拉滚动,不支持跳页:
SELECT * FROM t_order WHERE id > 100000 ORDER BY id LIMIT 20;这条SQL耗时仅0.02秒,性能提升64倍。
核心 SQL 优化前后性能对比柱状图:
7.2 JSON字段检索性能优化
现象描述
用户表,需要根据JSON内部city字段过滤数据,原始查询:
SELECT * FROM t_user WHERE info->>'city' = '西安';未优化执行耗时0.92秒。
看执行计划,数据库做全表扫描,遍历全部32万行,逐行解析JSON字段,CPU开销很高。不少开发者觉得金仓JSON性能差,大多是因为没有选对字段类型,也没有建立合适索引。
优化方案
1. 把JSON字段改成JSONB二进制格式,只有JSONB才支持GIN索引,普通JSON类型不支持。
2. 创建GIN倒排索引,专门用于JSONB键值检索:
CREATE INDEX idx_user_info_gin ON t_user USING gin(info);3. 修改查询语法,使用@>包含运算符,这样才能够命中GIN索引。
SELECT * FROM t_user WHERE info @> '{"city":"西安"}'::jsonb;这里踩过坑:修改字段、建好索引之后,继续使用原来->>语法查询,速度完全没有改善,依旧全表扫描。翻资料才弄明白,->>这种字段提取写法不会触发GIN索引,必须切换@>运算符,优化器才会选用索引。
优化效果
优化之后执行耗时0.04秒,性能提升23倍。执行计划显示走GIN索引扫描,只读取符合条件的记录,不再全表解析JSON。我也测试多条件组合查询,同样能够命中索引,表现稳定。
顺带对比MySQL8.0相同数据集,同样查询耗时0.31秒。金仓JSONB搭配GIN索引,这个场景的执行速度反而比MySQL快接近8倍,这点是我测试前没有预料到的。
八、金仓数据库个性化参数调优
刚安装完成的默认参数,是针对低配环境设计。想要充分发挥硬件能力,要结合自己机器硬件情况调整。金仓配置文件体系和PostgreSQL很接近,有PostgreSQL基础上手门槛不高。
8.1 核心配置文件路径
配置文件存放在实例数据目录:D:\Kingbase\ES\V9\data\kingbase.conf。
修改配置之前,强烈建议复制一份备份,参数改错导致实例无法启动的时候,可以直接恢复。修改配置之后,需要重启数据库实例才会生效。
8.2 本地化参数定制调整
我的测试机器内存16G,不能直接照搬服务器上那套参数,比如网上示例直接设置shared_buffers=8G,放在本地Windows环境会直接启动失败。参数需要结合本机剩余内存来权衡。
参数名 | 默认值 | 修改后的值 | 修改原因 |
shared_buffers | 128MB | 2GB | 共享数据缓冲区,官方建议物理内存1/8‑1/4;本机操作系统和其他软件会占用内存,设置2G比较稳妥,一开始尝试4G直接启动失败 |
work_mem | 4MB | 64MB | 单会话排序、哈希运算内存,提升order by、group by性能,减少磁盘临时文件生成,本地测试并发量不高,可以调大 |
maintenance_work_mem | 64MB | 256MB | 维护任务内存,建索引、vacuum操作速度更快;实测建立GIN索引从12秒缩短至5秒 |
effective_cache_size | 4GB | 8GB | 告知查询优化器系统可用缓存大小,会影响执行计划选择,调大之后优化器更倾向选择索引扫描 |
max_connections | 100 | 200 | 最大连接数,本地测试足够,连接数量太多会消耗大量内存资源 |
wal_buffers | 1MB | 16MB | WAL日志缓冲区,减少磁盘刷写次数,批量写入更加流畅 |
log_min_duration_statement | -1 | 1000ms | 记录执行耗时超过1秒的SQL,方便后期定位慢查询问题 |
8.3 参数生效与性能验证
修改完配置文件,重启金仓实例。可以在Windows服务管理器右键重启KingbaseES V9‑KINGBASE,也可以执行命令:
sys_ctl restart -D D:\Kingbase\ES\V9\data重启完成验证参数是否生效:
SHOW shared_buffers;返回结果输出2GB,说明配置加载成功。
我做一轮性能对比,调参前后数据:
深度分页SQL:0.07秒下降到0.062秒,性能提升约11%
JSON查询:0.04秒下降到0.037秒,性能提升约7%
批量插入一万条订单记录:1.2秒下降到0.7秒,性能提升42%
混合读写压测(100并发,合计一万次请求):TPS由320上涨到480,提升50%
整体性能提升很可观,写入性能改善尤为明显,调参之后性能基本和MySQL持平。
九、KWR性能报告实操,自主定位数据库瓶颈
金仓自带KWR性能报告,功能对标Oracle的AWR,排查数据库性能瓶颈很方便,不需要额外安装第三方组件。
9.1 KWR插件开启
我最开始直接调用快照函数,提示函数不存在,卡了半小时。查阅官方文档才知道,KWR属于可选插件,默认没有开启,需要手动加载。
开启步骤:
1. 修改kingbase.conf配置,增加配置项:
shared_preload_libraries = 'kwr'2. 重启数据库服务。
3. 连接数据库,创建扩展插件:
CREATE EXTENSION kwr;4. 执行快照函数做验证:
SELECT kwr_create_snapshot();执行无报错,代表插件已经正常启用。
9.2 生成性能报告实操
1. 采集第一份性能快照
SELECT kwr_create_snapshot();2. 运行20分钟模拟业务压力,我用Python脚本做混合读写,包含分页查询、JSON检索、订单新增、状态更新,模拟真实业务流量。
3. 业务压力跑完,采集第二份快照:
SELECT kwr_create_snapshot();4. 查询快照ID,确认快照信息:
SELECT snap_id, snap_time FROM sys_kwr_snapshot ORDER BY snap_id;5. 输出HTML格式性能报告:
SELECT kwr_report(1, 2, 'html');报告文件直接输出到数据目录,打开HTML就可以查看完整性能分析内容。
9.3 瓶颈分析与优化
借助这份报告,我发现本地环境三处真实问题。
长事务占用连接资源:有一条会话开启事务之后,长达12分钟没有提交,是我之前做测试忘记关闭。持续占用数据库连接资源。处理方案:测试环境建议开启自动提交;长业务事务务必及时提交;异常会话可以执行
SELECT pg_terminate_backend(会话PID);直接杀掉会话。全表扫描带来高IO:没有优化之前的JSON查询,占整体DB Time的40%,大量全表扫描拉高磁盘IO。对应解决办法,建立GIN索引,改写查询语句;优化完成后这块IO占比下降到5%以内。
WAL频繁刷盘:大量小批量写入,触发频繁WAL日志落盘。优化方式调大
wal_buffers参数;业务代码尽量合并做批量提交,优化后WAL写操作次数下降60%。
有这份报告,排查问题不用靠猜测。TOP慢SQL、等待事件、IO统计全部罗列清楚,就算经验不多也可以快速定位性能问题。
十、极简主备同步高可用测试
作为学习测试,我在本机搭建一套轻量化一主一备流复制架构,验证金仓流复制能力。不去搭建复杂集群,目标就是配置简单、能够复现。
轻量一主一备流复制高可用架构图:
10.1 主库配置
继续沿用原来54321端口实例当作主库,修改相关配置:
1. 创建专门用于复制的账号:
CREATE USER repl REPLICATION LOGIN PASSWORD 'Repl@2024';2. 修改D:\Kingbase\ES\V9\data\pg_hba.conf,增加一行配置,允许本机复制账号连接:
host replication repl 127.0.0.1/32 scram‑sha‑2563. 修改kingbase.conf,开启归档复制相关参数:
wal_level = replica max_wal_senders = 10 wal_keep_size = 1GB4. 重启主库实例,配置生效。
10.2 备库克隆与启动
直接使用sys_basebackup工具完整克隆主库数据,不需要手动初始化实例,保障两份数据初始状态完全一致。
1. 需要把D:\Kingbase\ES\V9\bin目录加到系统环境变量Path,不然cmd识别不到命令。
2. 以管理员身份启动cmd,运行克隆命令:
sys_basebackup -h 127.0.0.1 -p 54321 -U repl -D D:\Kingbase\ES\V9\data_standby -Fp -Xs -P -R3. 修改备库配置文件D:\Kingbase\ES\V9\data_standby\kingbase.conf,监听端口改成54322,防止和主库端口冲突。
4. 启动备库实例:
sys_ctl start -D D:\Kingbase\ES\V9\data_standby10.3 同步验证
1. 在主库执行SQL,查看备库复制连接状态:
SELECT pid, state, sync_state FROM sys_stat_replication;2. 同步验证:主库插入一条测试记录,到备库查询,同步延迟大概0.8秒,两边数据完全一致。
3. 故障切换简单测试:停止主库服务,备库执行提升命令,把备库切换为主库。
sys_ctl promote -D D:\Kingbase\ES\V9\data_standby整套轻量主备环境搭建,前后耗时不到半小时。针对中小型业务基础高可用需求,这套方案已经足够使用。
十一、迁移全流程踩坑总结
整套实操做完,大大小小碰到十多个问题。这里挑选11个印象很深的故障记录下来,大多是官方教程里面很少提及,只有动手实操才会撞上。
1. 安装路径带中文,实例初始化失败
遇到现象:初始化实例直接退出报错,提示初始化失败,错误码‑1。我折腾大概20分钟。
排查:最开始怀疑安装包损坏,重装两次问题依旧。翻看系统临时目录的安装日志,报编码错误invalid byte sequence for encoding UTF8,才定位是路径里面存在中文。
解决:卸载,重新安装到全英文路径D:\Kingbase\ES\V9,故障直接消失。
2. 管理员密码复杂度不达标,实例创建失败
遇到现象:设置简单密码,实例创建直接失败,提示密码不符合安全策略。耗时10分钟。
排查:单纯加长密码到8位,全部数字也不行。查阅初始化工具说明文档,才了解默认强制密码策略,大小写字母、数字、特殊符号,四项缺一不可。
解决:设置满足复杂度规则的密码,例如Test@2024,顺利完成实例创建。
3. KDT工具连接金仓,驱动版本不匹配
遇到现象:KDT配置目标库,测试连接抛出“无法创建连接,驱动类异常”,卡了30分钟。
排查:一开始拿通用PostgreSQL驱动,兼容性不行;网上下载若干版本金仓驱动,版本依旧不匹配。
解决:直接取用金仓安装包自带驱动D:\Kingbase\ES\V9\jdbc\kingbase8‑9.0.3.jar,版本匹配,一次连接成功。
4. 迁移完成自增主键插入报主键冲突
遇到现象:导入存量数据之后,新增写入抛出duplicate key value violates unique constraint,耗时25分钟。
排查:表结构里面序列对象还存在,但是序列当前值停留在1,数据表里面已经上百万行记录;KDT迁移不会自动同步序列的数值。
解决:手动同步序列与表最大ID,SELECT setval('t_order_id_seq', (SELECT MAX(id) FROM t_order));,问题解决。
5. SUBSTRING_INDEX自定义函数负数参数返回结果错误
遇到现象:自定义函数正数输入运行正常,负数下标输出结果和MySQL不一样,调试15分钟。
排查:函数内部加入raise notice打印数组长度、切片起止下标,发现数组下标从1开始,负数场景计算公式少加1。
解决:修正计算公式arr_len + count + 1,正数负数全部测试通过。
6. shared_buffers设置4G,数据库服务启动失败
遇到现象:修改参数重启实例,服务启动之后立刻停止,完全无法启动,折腾20分钟。
排查:查看data/sys_log目录数据库日志,报错共享内存映射失败。Windows平台对程序共享内存大小有限制,不能照搬Linux服务器大内存参数。
解决:将shared_buffers调整为2G,实例正常启动。
7. JSON字段创建GIN索引直接报错
遇到现象:执行建索引语句,报错data type json has no default operator class for access method gin,耗费40分钟。
排查:反复核对SQL语法没有错误,查阅官方文档,普通json存储格式不支持GIN索引,只有jsonb二进制类型才支持。
解决:先把字段类型改成jsonb,再创建GIN索引,语句正常执行。
8. 调用KWR快照,提示函数不存在
遇到现象:执行kwr_create_snapshot(),提示函数不存在,卡30分钟。
排查:一开始误以为个人版直接砍掉KWR功能,翻阅手册才知道KWR是可选插件,不会默认加载。
解决:修改shared_preload_libraries参数,重启实例,执行CREATE EXTENSION kwr;创建扩展,函数恢复正常。
9. sys_basebackup命令提示不是内部或外部命令
遇到现象:cmd执行备份克隆命令,系统提示找不到这条命令,耗时10分钟。
排查:金仓bin目录没有自动写入系统环境变量PATH。
解决:把D:\Kingbase\ES\V9\bin添加进系统Path环境变量,关闭重新打开cmd,命令识别正常。
10. 备库启动失败,提示文件权限不足
遇到现象:启动备库实例报错could not open configuration file: Permission denied,耗时18分钟。
排查:通过sys_basebackup克隆出来的数据目录,Windows文件权限没有继承,System系统用户缺少读写权限。
解决:右键data_standby文件夹,属性‑安全,添加System账号,授予完全控制权限,重启实例恢复正常。
11. KDT开启增量同步,程序闪退丢失任务进度
遇到现象:设置8线程跑增量同步,运行十几分钟KDT无响应闪退,全部任务进度丢失,耗时22分钟。
排查:打开任务管理器观察内存占用,KDT进程内存飙升接近4G,发生内存溢出;本机总共16G内存,同时还要跑两套数据库实例。
解决:并发线程下调至4,内存稳定维持2G上下,增量同步全程稳定运行。
十二、总结与国产化实践感悟
整套实操全部跑通,前后利用三天业余碎片时间完成。我的切身感受:国产数据库,并没有网上传言那样处处难用。
和不少同行一样,过去我也主观觉得国产数据库“能用,但不好用”,性能短板、适配麻烦、故障资料少。但这次完整走完从安装、迁移、调优,再到搭建主备的全部流程之后,体会完全不一样。只要提前把兼容性评估做到位,针对性完成表结构、自定义函数适配,结合业务场景调整索引和数据库参数。金仓KES处理核心业务场景,性能完全不输MySQL,部分场景,例如JSON检索,表现反而更好。
对我个人来说,这份实操最大价值,并不是最后拿到一组性能数字。而是一步步踩坑、定位问题、不断试错解决的整个过程。不管是安装阶段踩路径的坑,迁移阶段处理语法兼容,调参的时候反复试错,没有哪一步看一遍教程就可以直接完美跑通,大多需要反复查看日志、翻阅官方文档才能搞定。
这也是我觉得学习国产化数据库最关键的点:不要只看网上别人的测评文章,条件允许,自己动手完整部署、迁移、调优一遍。亲身测试之后,才能真正摸清楚这套数据库的长处和短板,心里才有底。
对于中小型业务做国产化数据库替换,不用有很重的畏难心理。可以先在本地测试环境跑完整套迁移流程,评估适配工作量和性能表现,再逐步切业务流量,整体风险可控,成本也不会很高。后续我还打算继续测试存储过程、触发器,还有其他更加复杂的业务场景,积累更多国产化落地实操经验。