KingbaseES 的 SQL Server 兼容性测试
前言:为什么要做这个测试?
说到国产数据库替代,相信很多朋友都会头疼。毕竟公司用了这么多年的 SQL Server,突然要换成国产数据库,光想想就觉得工作量巨大。不过呢,KingBaseES(电科金仓数据库)这款国产数据库还真的挺用心,它专门做了对 SQL Server 的兼容。
那这个兼容到底有什么好处呢?我给大家说说:
- 省钱省力:原来基于 SQL Server 开发的系统,基本上不用大改就能迁过来
- 经验不浪费:团队之前积累的 SQL Server 技术和代码都能继续用
- 学习成本低:不用从头学新语法,DBA 和开发人员都能快速上手
好了,话不多说,咱们今天就实际测试一下,看看金仓数据库到底能不能扛得住 SQL Server 的那些"独门绝技"。
第一步:准备工作
1. 下载安装包
首先呢,咱们得去金仓官网把安装包下载下来。根据你测试机的系统选对应的版本就行。我这次测试用的是 Linux 64 位版本:点击跳转

2. 下载授权文件
别忘了去官网申请一个授权文件,不然装完也用不了。授权文件下载地址
根据自己的需求去选择授权文件。
3. 开始安装
安装过程其实挺简单的,跟着下面的命令敲就行:
bash
# 挂载 ISO 镜像
[root@testdb opt]# mount -o loop KingbaseES_V009R004C012B0006_Lin64_install.iso /mnt
# 创建安装目录
[root@testdb opt]# mkdir -p /data/KS
[root@testdb opt]# chown -R kingbase:kingbase /data/KS
# 切换到 kingbase 用户安装
[root@testdb mnt]# su - kingbase
[kingbase@testdb ~]$ cd /mnt
[kingbase@testdb mnt]$ ./setup.sh
# 安装完成后执行 root 脚本
[root@testdb opt]# /data/KS/install/script/root.sh
如果看到下面这个提示,就说明装好了:
Starting KingbaseES V9:
waiting for server to start.... done
server started
KingbaseES V9 started successfully
4. 确认安装情况
连上数据库看看:
bash
[kingbase@testdb ~]$ ksql -U system -p 54321 -W -d template1
Password:
Licesen Type: SALES-企业版.
Type "help" for help.
template1=#
然后检查一下数据库模式,看看是不是 SQL Server 兼容模式:
sql
template1=# show database_mode;
database_mode
---------------
sqlserver
(1 row)
好耶!确实是 SQL Server 模式。再看看版本号:
sql
template1=# select version();
version
-------------------------
KingbaseES V009R004C012
(1 row)
第二步:SQL 兼容性实战测试
好了,前期准备工作做完了,现在开始重头戏------测试各种 SQL Server 特有的数据类型和语法。
测试 1:ROWVERSION 数据类型
这是个啥?
简单说,rowversion
是 SQL Server 里用来做乐观锁的。它有几个特点:
- 自动更新:你插入或更新数据时,这列会自动变
- 全局唯一:整个数据库里的值都不重复
- 不能手动改:你想写入值都不行
开始测试
首先要注意一个坑:在 test 库或者 kingbase 库里直接用 rowversion
会报错。所以咱们得自己建个库:
sql
master=# create database sky;
CREATE DATABASE
master=# \c sky
Password:
You are now connected to database "sky" as userName "system".
创建一个带 rowversion
字段的表:
sql
sky=# CREATE TABLE ExampleTable (
ID int PRIMARY KEY,
Data varchar(100),
Version rowversion
);
CREATE TABLE
插入几条数据试试:
sql
sky=# insert into ExampleTable(id,data) values(1,'a');
INSERT 0 1
sky=# select * from ExampleTable;
ID | Data | Version
----+------+--------------------
1 | a | 0x0000000000000001
(1 row)
看到没?Version
列自动有值了!再插入一条:
sql
sky=# insert into ExampleTable(id,data) values(2,'b');
INSERT 0 1
sky=# select * from ExampleTable;
ID | Data | Version
----+------+--------------------
1 | a | 0x0000000000000001
2 | b | 0x0000000000000002
(2 rows)
版本号自动递增了,漂亮!
现在试试更新数据:
sql
sky=# update ExampleTable set data='c' where id=2;
UPDATE 1
sky=# select * from ExampleTable;
ID | Data | Version
----+------+--------------------
1 | a | 0x0000000000000001
2 | c | 0x0000000000000003
(2 rows)
注意看,更新后版本号从 0x02
跳到了 0x03
,说明版本号是全局递增的!
我还试了试手动插入 rowversion
的值,结果不出所料地报错了:
sql
sky=# insert into ExampleTable values(3,'d','a');
ERROR: column "Version" is of type rowversion but expression is of type varchar
测试结论
金仓数据库对 rowversion
的支持非常到位,跟 SQL Server 的行为基本一致!
测试 2:SQL_VARIANT 数据类型
这是个啥?
sql_variant
可厉害了,它是个"万能"数据类型,一列里可以存不同类型的数据。比如第一行存整数,第二行存字符串,第三行存日期时间------都没问题!
开始测试
创建表:
sql
sky=# CREATE TABLE VariantTable (
ID int PRIMARY KEY,
VariantData sql_variant
);
CREATE TABLE
往里塞各种类型的数据:
sql
-- 插入整数
sky=# INSERT INTO VariantTable VALUES (1, 123);
INSERT 0 1
-- 插入字符串
sky=# INSERT INTO VariantTable VALUES (2, 'Hello World');
INSERT 0 1
-- 插入小数
sky=# INSERT INTO VariantTable VALUES (3, 3.14159);
INSERT 0 1
-- 插入日期时间
sky=# INSERT INTO VariantTable VALUES (4, GETDATE());
INSERT 0 1
全都成功了!现在试试查询数据的类型信息:
sql
sky=# SELECT
SQL_VARIANT_PROPERTY(VariantData, 'BaseType') AS DataType,
SQL_VARIANT_PROPERTY(VariantData, 'Precision') AS Precision,
SQL_VARIANT_PROPERTY(VariantData, 'Scale') AS Scale,
SQL_VARIANT_PROPERTY(VariantData, 'TotalBytes') AS StorageSize
FROM VariantTable;
DataType | Precision | Scale | StorageSize
----------+-----------+-------+-------------
int | 10 | 0 | 10
varchar | 0 | 0 | 19
numeric | 6 | 5 | 20
datetime | 23 | 3 | 14
(4 rows)
太棒了!可以准确地识别出每个值的类型。
再试试类型转换:
sql
sky=# SELECT ID, CAST(VariantData AS varchar(100)) AS StringValue
FROM VariantTable;
ID | StringValue
----+---------------------
1 | 123
2 | Hello World
3 | 3.14159
4 | Jul 15 2025 7:36PM
(4 rows)
完美!
测试结论
sql_variant
这个复杂的数据类型,金仓数据库也支持得很好,包括相关的函数都能用。
测试 3:UNIQUEIDENTIFIER 数据类型
这是个啥?
这就是大家常说的 GUID(全局唯一标识符),128 位的唯一 ID,长这样:6F9619FF-8B86-D011-B42D-00C04FC964FF
开始测试
创建表,使用 NEWID()
函数自动生成 GUID:
sql
sky=# CREATE TABLE Users (
UserID UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),
UserName NVARCHAR(50) NOT NULL,
Email NVARCHAR(100)
);
CREATE TABLE
插入数据:
sql
sky=# INSERT INTO Users (UserID, UserName, Email)
VALUES (NEWID(), 'JohnDoe', 'john@example.com');
INSERT 0 1
sky=# select * from Users;
UserID | UserName | Email
--------------------------------------+----------+------------------
5B48E470-9698-4D1C-915C-48B2EF3C5674 | JohnDoe | john@example.com
(1 row)
试试用 GUID 来查询:
sql
sky=# select * from Users where userid='5B48E470-9698-4D1C-915C-48B2EF3C5674';
UserID | UserName | Email
--------------------------------------+----------+------------------
5B48E470-9698-4D1C-915C-48B2EF3C5674 | JohnDoe | john@example.com
测试结论
GUID 的生成和查询都没问题,完美兼容!
测试 4:SYSNAME 数据类型
这是个啥?
SYSNAME
其实就是 NVARCHAR(128) NOT NULL
的别名,专门用来存储数据库对象的名字(表名、列名、存储过程名之类的)。
开始测试
创建表:
sql
sky=# CREATE TABLE DatabaseObjects (
ObjectID INT IDENTITY PRIMARY KEY,
ObjectName SYSNAME NOT NULL,
ObjectType SYSNAME NOT NULL
);
sky=# INSERT INTO DatabaseObjects (ObjectName, ObjectType)
VALUES ('Customers', 'TABLE'), ('usp_GetOrders', 'PROCEDURE');
INSERT 0 2
sky=# select * from DatabaseObjects;
ObjectID | ObjectName | ObjectType
----------+---------------+------------
1 | Customers | TABLE
2 | usp_GetOrders | PROCEDURE
(2 rows)
不过要注意一个细节:如果想在动态 SQL 里用变量,金仓数据库需要用 begin...end
块包起来:
sql
sky=# \set SQLTERM /
sky=# begin
DECLARE @TableName SYSNAME = 'DatabaseObjects';
DECLARE @SQL NVARCHAR(MAX) = 'SELECT * FROM ' + QUOTENAME(@TableName);
EXEC sp_executesql @SQL;
end;
/
ObjectID | ObjectName | ObjectType
----------+---------------+------------
1 | Customers | TABLE
2 | usp_GetOrders | PROCEDURE
(2 rows)
测试结论
SYSNAME
类型支持良好,只是动态 SQL 的写法稍有差异。
第三步:SQL 语句兼容性测试
数据类型测完了,再来看看 SQL 语句的兼容情况。
测试 1:LIMIT 子句
sql
sky=# SELECT * FROM DatabaseObjects limit 1;
ObjectID | ObjectName | ObjectType
----------+------------+------------
1 | Customers | TABLE
(1 row)
虽然 LIMIT
是 PostgreSQL 的语法,但在 SQL Server 兼容模式下也能用,方便!
测试 2:索引操作
创建索引:
sql
sky=# create index idx_data on ExampleTable(data);
CREATE INDEX
重建索引(两种写法都支持):
sql
-- 方式一
sky=# reindex index idx_data;
REINDEX
-- 方式二(SQL Server 原生语法)
sky=# ALTER INDEX IDX_DATA ON ExampleTable REBUILD;
WARNING: Does not verify whether index is related to table
REINDEX
测试 3:锁等待与 NOWAIT
这个测试挺有意思的。我开了两个会话:
会话 A 先执行更新但不提交:
sql
sky=# \set AUTOCOMMIT off
sky=# UPDATE ExampleTable SET data = 'bbbb' WHERE id=1;
UPDATE 1
会话 B 尝试更新同一行,会一直等待:
sql
sky=# UPDATE ExampleTable SET data = 'bbbb' WHERE id=1;
-- 一直等待...
^CCancel request sent
ERROR: canceling statement due to user request
但如果使用 NOWAIT
提示,可以更新其他行:
sql
sky=# UPDATE ExampleTable WITH (NOWAIT) SET data = 'cccc' WHERE id=2;
UPDATE 1
这个特性跟 SQL Server 一模一样!
总结:值得信赖的兼容性
测试做完了,说说我的感受:
金仓数据库对 SQL Server 的兼容性真的做得很扎实!从测试结果来看:
✅ 数据类型支持全面 :ROWVERSION
、SQL_VARIANT
、UNIQUEIDENTIFIER
、SYSNAME
这些 SQL Server 特有的数据类型都能用
✅ 语法高度兼容:常用的 T-SQL 语法基本都能直接跑,兼容度能达到 90% 以上
✅ 行为一致性好 :不只是能用,具体的行为表现(比如 rowversion
的自动更新机制、锁等待机制)都跟 SQL Server 保持一致
✅ 迁移成本低:对于 SQL Server 用户来说,切换到金仓数据库基本不需要大改代码
所以如果你的公司正在考虑国产数据库替代方案,金仓数据库确实是个不错的选择。既能保证业务连续性,又能实现技术自主可控,还能节省不少迁移成本------一举多得!
当然,具体使用时还是建议针对自己的业务场景做充分测试,毕竟每个系统的情况都不一样。但从兼容性的角度来说,金仓数据库已经交出了一份令人满意的答卷。
好了,今天的测试分享就到这里。希望对正在做技术选型或者数据库迁移的朋友有所帮助!有问题欢迎交流~