电科金仓在 Gitee 上发布了 kes-skills,包含 31 个供 AI 助手调用的技能。按官方介绍,安装后可以由智能体根据任务调用相应的技能。
我手上有两套金仓库,分别采用 Oracle 和 MySQL 兼容模式。8 月 26 日,我拿 kes-skills 里的示例做了一轮对照测试:先执行原文中的 SQL,遇到报错再尝试改写,记录两套库的执行结果。
测试时,我通过 ksql 执行 SQL,在命令行验证部分运维操作,没有接入智能体。
两套金仓库和用来对照的 Oracle 12c 在同一台机器上。
| 项目 | Oracle 兼容库 | MySQL 兼容库 | 同机 Oracle 12c |
|---|---|---|---|
| 数据库版本 | KingbaseES V009R002C014 | KingbaseES V009R003C018 | Oracle 12.1.0.1 Enterprise Edition |
| database_mode | oracle | mysql | 不适用 |
| 监听端口 | 54322 | 54323 | 未列出 |
| 初始化 | initdb —dbmode=oracle | initdb -m mysql | 不适用 |
| 数据目录 | /home/kingbaseo/data | /home/kingbasemy/data | 未列出 |
| max_connections | 100 | 100 | 未列出 |
| shared_buffers | 128MB | 128MB | 未列出 |
| work_mem | 4MB | 4MB | 未列出 |
| sys_stat_statements.track | none | none | 不适用 |
| 客户端 | ksql V009R002C014 | ksql V009R003C018 | sqlplus / as sysdba |
两套库分别使用各自安装目录下的
Server/bin 和
Server/lib,通过 ksql 连接
127.0.0.1,用户为
system,库名为
test。测试表统一以
skill_lab_ 开头,测试结束后删除。整个过程没有修改
kingbase.conf,也没有重启数据库。
两套库的版本不同,下面的执行差异也可能与版本有关,不能全部归因于兼容模式。
测试范围如下:
| 技能 | 测试内容 |
|---|---|
| kes-oracle-compat | SHOW oracle_compatible、NVL、DECODE、SYSDATE、dual、空串、ROWNUM、ADD_MONTHS、NUMBER/VARCHAR2、CONNECT BY、序列 |
| kes-core | sys_tables、RANK、递归 CTE、RANGE 分区、json/jsonb、ON CONFLICT |
| kes-plsql | 技能页匿名块、DO 块、CREATE FUNCTION |
| kes-user-mgmt | CREATE USER、授权、只读账号 SELECT/INSERT |
| kes-index-design | BTree、部分索引、EXPLAIN |
| kes-backup | sys_tablespace_size、sys_dump 及恢复 |
| kes-db-optim | SHOW shared_buffers / work_mem / max_connections、ANALYZE |
| kes-sql-tuning、kes-monitoring | EXPLAIN、统计视图、KWR 函数名 |
这次实验不涉及 Java、Python 连接、Docker 安装、HA、KDTS,以及
kes-migration、
kes-vector、
kes-mcp 和 KRB/KRC/PITR。
kes-oracle-compat 中用下面这条命令查询兼容参数:
SHOW oracle_compatible;
我在两套库上执行,都报参数不存在:
ERROR: unrecognized configuration parameter "oracle_compatible"
改用
SHOW database_mode,分别查到
oracle 和
mysql。
技能页的迁移对照表列出了几组替代写法:NVL 对应 COALESCE,DECODE 对应 CASE,CONNECT BY 对应 WITH RECURSIVE。我先按 Oracle 的写法执行,检查两套库的支持情况。下面摘录部分测试语句,省略了数据准备和序列创建过程。
SELECT NVL(NULL, 'x');SELECT DECODE(1, 1, 'yes', 'no');SELECT SYSDATE;SELECT * FROM dual;SELECT CASE WHEN '' IS NULL THEN 'empty_is_null' ELSE 'empty_is_empty' END;SELECT ROWNUM FROM (SELECT 1 AS a) t;SELECT ADD_MONTHS(DATE '2024-01-31', 1);CREATE TABLE skill_lab_ora (id NUMBER(10) PRIMARY KEY, name VARCHAR2(32));CREATE TABLE skill_lab_emp (empno int PRIMARY KEY, ename varchar(16), mgr int);SELECT empno, ename, mgr, LEVEL FROM skill_lab_empSTART WITH mgr IS NULL CONNECT BY PRIOR empno = mgr;SELECT skill_lab_seq.NEXTVAL; SELECT nextval('skill_lab_seq');
| 语句 | Oracle 兼容库(54322) | MySQL 兼容库(54323) | 同机 Oracle 12c |
|---|---|---|---|
| NVL(NULL,’x’) | x | x | x |
| DECODE(1,1,’yes’,’no’) | yes | ERROR: function DECODE(…) does not exist | yes |
| SYSDATE | 2026-08-26 09:42:17 | 2026-08-26 09:42:17 | 26-AUG-26 |
| SELECT * FROM dual | 一行 X | 一行 X | 一行 |
| ‘’ IS NULL | empty_is_null | empty_is_empty | empty_is_null |
| ROWNUM | 1 | 1 | 1 |
| ADD_MONTHS(DATE ‘2024-01-31’,1) | 2024-02-29 00:00:00 | ERROR: function ADD_MONTHS(…) does not exist | 未跑 |
| NUMBER + VARCHAR2 | 成功 | 成功 | 未列出结果 |
| CONNECT BY + LEVEL | 4 行,lvl=1/2/2/3 | 4 行,一样 | 未列出结果 |
| seq.NEXTVAL | 1 然后 2 | 1 然后 2 | 未列出结果 |
在这套 Oracle 兼容库上,NVL、DECODE、CONNECT BY 都能执行。对这几个示例,没有必要按对照表改写,增加代码修改和评审的工作量。MySQL 兼容库支持这里的 CONNECT BY,但执行 DECODE 和 ADD_MONTHS 时报函数不存在,这两处需要改写。
空串的处理有区别。Oracle 兼容库和 Oracle 12c 把
'' 当作 NULL,MySQL 兼容库保留为空字符串。表中的 CASE 语句在两套库上执行成功,却进入了不同的分支。迁移时如果只检查是否报错,就会漏掉这种差异。业务中涉及
IS NULL、唯一约束或 NVL/COALESCE 的地方,还需要补充空串用例,核对处理结果。
Oracle 兼容库的 ADD_MONTHS 输出中包含
00:00:00。接口如果按字符串比较日期,需要核对这里的输出格式。
这一部分测试了系统表查询、窗口函数、递归 CTE、分区、JSON 取值和 UPSERT。以下为语句节选,省略号处需补全后执行。
SELECT schemaname, tablename FROM sys_tables WHERE schemaname NOT LIKE 'sys%' LIMIT 5;SELECT RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) FROM ...;WITH RECURSIVE org AS (SELECT 1 AS id, NULL::int AS pid, 1 AS depth UNION ALL ...);CREATE TABLE skill_lab_sales (...) PARTITION BY RANGE (sold_at);SELECT '{"a":1}'::json ->> 'a';INSERT ... ON CONFLICT (id) DO UPDATE ...;
| 语句 | Oracle 兼容库 | MySQL 兼容库 |
|---|---|---|
| sys_tables | 有结果;public 下能看到业务表 | 有结果;过滤 sys% 后仍能查到 pg_catalog 的表 |
| RANK() 窗口 | 3 行,排序正确 | 同样 |
| 递归 CTE(id 写成 int) | 3 行 | ERROR: column 1 has type integer in non-recursive term but type bigint overall |
| RANGE 分区插入 | count=1 | count=1 |
| json ->> | 1 | ERROR: syntax error, unexpected IDENT_P at end of jsonpath input |
| jsonb ->> | 1 | 1 |
| ON CONFLICT | v 变成 new | v 变成 new |
MySQL 兼容库的递归 CTE 报了类型不一致:非递归部分是 integer,整个 CTE 是 bigint。我将非递归部分的 id 显式转换为 bigint 后,执行通过,递归逻辑没有改动。
JSON 取值也遇到了报错。在 MySQL 兼容库上,
::json ->> 解析失败;将这个示例中的类型换成
jsonb 后,返回值为 1,与 Oracle 兼容库一致。
技能页给出的匿名块是:
BEGIN DECLARE v_count INT; SELECT count(*) INTO v_count FROM sys_tables; RAISE NOTICE '表数量: %', v_count;END;
我在两套库上执行这段代码,都在 DECLARE 处遇到语法错误。改成
DO $$ ... $$ 后执行通过,Oracle 兼容库输出
NOTICE cnt=129,MySQL 兼容库输出
cnt=125。
技能页的函数示例使用
CREATE OR ALTER,没有指定
LANGUAGE。我将示例改成 plpgsql 写法,创建函数后执行
SELECT skill_lab_bonus(15000,'A'),两套库都返回
3000.00。这里验证通过的是改写后的版本。
我按技能页的步骤执行
CREATE USER、
GRANT CONNECT、
GRANT SELECT 和
REVOKE INSERT,再切换到只读账号
skill_lab_r,分别执行查询和插入操作。
| 操作 | Oracle 兼容库 | MySQL 兼容库 |
|---|---|---|
| CREATE USER + GRANT SELECT | 成功 | 成功 |
| 只读 SELECT count(*) | 1 | 1 |
| 只读 INSERT | ERROR: permission denied for table skill_lab_acl | 同样 |
执行
REVOKE INSERT 时,两套库都提示
WARNING: unable to revoke privilege not granted。新建角色没有 INSERT 权限,因此没有可撤销的授权。切换账号后的测试结果也符合预期:查询成功,插入时报权限错误。测试结束后,我删除了账号和测试表。
我准备了 200 行数据,建了 BTree 和部分索引,设置
enable_seqscan=off 后执行:
EXPLAIN SELECT * FROM skill_lab_idx WHERE name='n10';
两套库的执行计划中都有
Index Scan using idx_skill_lab_name。在
sys_indexes 中能查到
pkey、
idx_skill_lab_name 和
idx_skill_lab_active。
这条执行计划是在
enable_seqscan=off 的条件下得到的,可以确认查询能够使用
idx_skill_lab_name,但不能据此判断默认配置下的索引选择或性能收益。GIN/GiST 不在本次测试范围内。
我查询了默认表空间大小,用
sys_dump 导出
skill_lab_dump,再通过
ksql -f 恢复。另外检查了
shared_buffers、
work_mem 和
max_connections,并执行
ANALYZE。
| 任务 | Oracle 兼容库 | MySQL 兼容库 |
|---|---|---|
| sys_tablespace_size | 901 MB | 82 MB |
| sys_dump 后恢复 SELECT count(*) | 1 | 1 |
| dump 文件头 | Dumped from database version 12.1 | 同类格式 |
| ANALYZE | 成功 | 成功 |
导出文件头中的
Dumped from database version 12.1 与
version() 查询到的 KES 版本号不同。登记数据库版本时,应以
version() 的结果为依据,或核对安装目录中的
KESRealPro。
本次备份恢复使用了一张只有一行数据的测试表,恢复后的行数与备份前一致,未验证完整数据库的恢复。
kes-monitoring 和
kes-sql-tuning 中使用的是
sys_stat_statements。两套库都安装了扩展,版本分别为 1.12 和 1.11,
sys_stat_statements.track 均为
none。我也查询了
pg_stat_statements,两套库都报
relation does not exist。这里需要使用金仓的视图名,并检查 track 的采集设置。
对于 Skill 中的
CALL sys_kv_wrm_take_snapshot(),我用
to_regproc 查询,两套库都返回空值。不过,
ps 中能看到
kwr collector 进程,配置中也 preload 了
sys_kwr。这些信息还不足以判断 KWR 功能是否可用,需要进一步核对本库提供的函数及调用方式。这次没有执行快照验证。
对照执行计划时,我还发现 EXPLAIN 文本中的
pg_class 显示为
_rel。
我还做了客户端交叉连接测试:用 Oracle 兼容库的 ksql 连接 54323,用 MySQL 兼容库的 ksql 连接 54322,
SELECT version() 都执行成功,返回对端的服务端版本。因此,连接成功不能用来确认客户端路径配置正确。两套库的脚本需要分别配置 BIN、LIB、端口和用户,执行前核对服务端版本。
这次实测中,只读账号、分区、窗口函数和单表备份恢复都得到了预期结果,kes-skills 中的这些示例可以作为开发和运维的参考。需要修改的地方也有:兼容参数、匿名块写法,以及 MySQL 兼容库上的部分函数和类型处理,都遇到了问题。
迁移对照表中的替代写法,也需要根据目标库取舍。这套 Oracle 兼容库已经支持本次测试中的 NVL、DECODE、CONNECT BY,保留原 SQL 可以减少改造工作。对于空串这类语法能执行、结果却有差异的情况,还需要通过业务回归确认影响。
如果后续更新这套 Skill,我建议在示例旁标注验证过的版本和兼容模式,并补齐建表语句、测试数据及预期结果。这样,无论手工执行还是交给智能体调用,使用者都有一份可供复测的完整示例,遇到差异也方便核对。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/23825935/viewspace-3181035/ ,如需转载,请注明出处,否则将追究法律责任。