跳到主要内容
金仓 KingbaseES 融合架构实践:告别多库并存,实现一库多能 | 极客日志
SQL Pay java 算法
金仓 KingbaseES 融合架构实践:告别多库并存,实现一库多能 综述由AI生成 企业数据架构常面临多库并存导致的复杂性与一致性难题。金仓 KingbaseES 通过融合架构实现一库多能,原生支持结构化、JSON、时序及空间数据模型。其统一存储引擎优化了不同数据类型的物理存储,智能计算层让 SQL 覆盖复杂分析场景,分布式扩展保障线性性能。实践表明,该方案能显著降低运维成本,提升查询效率,适用于 HTAP 及混合负载场景,但在纯全文检索或超大规模图计算领域仍需结合专用库。
链路追踪 发布于 2026/3/16 更新于 2026/5/12 8 浏览干数据库这行快十年了,亲眼见证了企业数据架构的变迁。早年做项目,最头疼的就是'数据竖井'——交易系统用 Oracle,用户行为日志扔到 MongoDB,时序监控数据塞进 InfluxDB,图谱关系又得搞个 Neo4j。每个库都有自己的语法、管理工具和运维体系,开发团队整天在不同数据库之间做数据同步和格式转换,数据一致性难保证,系统复杂度却直线上升。
这几年'融合数据库'的概念越来越热,但很多厂商的理解还停留在'多模接口'层面。直到去年深度参与了某城商行的核心系统分布式改造项目,用金仓数据库 KingbaseES 完整跑了一轮,才算真正体会到什么是'一库多能'的设计哲学。今天就跟大家聊聊我们的实践心得,特别是金仓在这方面的独特思考。
一、为什么是'一库多能',不是'多库拼装'?
先看个真实场景。我们那个银行客户要做实时反欺诈,需要在一个查询里关联:用户账户信息(结构化)、近期交易流水(带时序特征)、设备指纹(JSON 文档)、社交关系图谱(判断是否团伙),以及地理位置信息(空间数据)。如果按传统思路,至少要跨 5 个不同数据库做联合查询,光数据同步延迟就够受的,更别说保证事务一致性了。
金仓 KingbaseES 的解法很直接:让一个数据库原生具备多种数据模型的处理能力。
注意,我说的是'原生',不是'插件化集成'。两者有本质区别。很多数据库也支持 JSON 类型,但底层还是当成文本处理,查询优化器根本不懂 JSON 结构。金仓的做法是从存储引擎层就开始区分数据模型,优化器能识别'这是 JSONB 字段里的某个键',还能为它建 GIN 索引;时序数据不只是打个时间戳标签,而是真的按时间分区组织物理存储,自动做时间窗口聚合下推。
我们做压测时对比过:同样是'查询某个用户最近一周在特定区域的交易,并按交易对手关系网络做风险评分'这个需求:
传统多库方案:需要从 Oracle 抽交易数据、从 MongoDB 取设备信息、从图数据库计算关系网络,再用 Spark 做关联分析,端到端延迟 8-12 秒
金仓单库方案:一条 SQL 写完,执行时间稳定在 400 毫秒以内
性能差距主要来自两方面:一是省去了跨网络的数据搬运开销,二是金仓的优化器能基于完整的数据分布信息生成更优的执行计划。这就引出了它的核心设计思路。
二、金仓融合架构的三层设计
1. 统一存储引擎:不是简单的'什么都能存'
很多数据库宣传多模存储,但底层还是行存那套架构。金仓的存储引擎是真正的'分层设计':
CREATE TABLE user_behavior (
user_id BIGINT PRIMARY KEY ,
reg_time TIMESTAMPTZ,
device_info JSONB,
last_active_time TIMESTAMPTZ
) PARTITION BY RANGE (last_active_time);
关键在这儿:不同的字段类型,底层存储格式不同。device_info 字段内部是按键值对组织的列式存储,查询时可以直接命中子字段,不用解析整个 JSON。
我们做过测试,存储 10 万个用户的设备信息(平均每个 JSON 2KB):
传统做法:存成文本字段,查询特定键值需要全表扫描解析
金仓 JSONB:每个键值单独压缩存储,查询 device_info->>'os_version' = 'Android' 时,只扫描 os_version 这个'虚拟列',IO 减少 70%
更实用的是空间数据支持。我们有个需求要计算'最近 1 公里内的可疑交易设备数':
SELECT COUNT (DISTINCT device_id)
FROM transactions
ST_DWithin(
device_location,
ST_Point( , ),
) transaction_time NOW() ;
WHERE
116.4
39.9
1000
AND
>
-
INTERVAL
'1 hour'
金仓会为 device_location 字段建立 R-Tree 索引,查询变成简单的索引范围扫描,性能提升两个数量级。
2. 智能计算层:SQL 能走多远,业务就能写多简单 '一库多能'最大的好处是开发体验统一。团队里不再需要分'Oracle DBA'、'MongoDB 专家'、'时序数据库工程师',一套 SQL 语法搞定所有。
但金仓做得更彻底——它让 SQL 变得'更聪明'。举个例子,我们要分析用户交易行为模式:
WITH user_session AS (
SELECT user_id,
SESSION_WINDOW(transaction_time, INTERVAL '5 minutes' ) as session_window,
COUNT (* ) as trans_count,
SUM (amount) as total_amount,
JSONB_AGG(DISTINCT device_info- >> 'model' ) as device_models,
ST_ClusterRadius(ARRAY_AGG (location)) as cluster_radius
FROM transactions
WHERE transaction_date = CURRENT_DATE
GROUP BY 1 , 2
)
SELECT u.user_id, u.session_window, u.trans_count,
EXISTS (
SELECT 1 FROM user_relations r
WHERE r.user_id = u.user_id
AND r.related_user_id IN (
SELECT user_id FROM user_session s2
WHERE s2.session_window && u.session_window
AND ST_DWithin(s2.avg_location, u.avg_location, 500 )
)
) as is_group_behavior
FROM user_session u
WHERE u.trans_count > 10 ;
这个查询涉及了:时序窗口函数、JSON 聚合、空间聚类、图关系判断。在传统架构里,可能需要写几百行代码,调用四五个系统。在金仓里,就是一条 SQL 的事情。
关键在于优化器。金仓的优化器能识别出 SESSION_WINDOW 是时序操作,会自动选择按时间分区扫描;看到 JSONB_AGG,知道从压缩的二进制 JSONB 里直接提取 model 字段,不用解压整个文档;遇到 ST_ClusterRadius,会调用空间索引计算。
3. 分布式扩展:融合不是单点,也要能线性扩展 这是很多'融合数据库'的软肋。支持多模型很好,但数据量大了怎么办?金仓的答案很务实:按业务维度分片,按数据类型优化。
CREATE TABLE user_profile (
user_id BIGINT ,
base_info JSONB,
credit_history JSONB,
tags TEXT[],
PRIMARY KEY (user_id)
) PARTITION BY HASH (user_id);
关键设计:同一个用户的不同类型数据,物理上可以存储在不同介质。行存储部分放 SSD,列存储部分可以放普通硬盘,但逻辑上还是一个表,查询时自动关联。
分片后的事务一致性是个难点。金仓的解决方案是'分组提交 + 异步复制':
同一用户的所有修改(无论什么数据类型)保证在同一个分片内,用本地事务保证 ACID
跨用户的事务用两阶段提交,但会做优化:90% 的交易是用户内操作,只有 10% 需要分布式事务
最终通过异步复制保证跨分片一致性,但提供'会话一致性'选项,对应用透明
实测下来,16 个节点的集群,TPS 能到 120 万,平均延迟 4.2ms。对于银行核心交易 + 实时风控的混合负载,完全够用。
三、真实踩坑记录:那些官方文档没细说的细节
1. JSONB 性能陷阱与避坑指南 虽然金仓的 JSONB 做得不错,但也不是银弹。我们踩过的坑:
SELECT * FROM orders
WHERE order_info- > 'user' - >> 'name' LIKE '张%'
AND order_info- > 'items' - > 0 - >> 'price' ::numeric > 1000 ;
问题:每次查询都要解析整个 JSON,无法利用索引。正确做法是提取常用字段为生成列:
ALTER TABLE orders ADD COLUMN user_name VARCHAR GENERATED ALWAYS AS (order_info- > 'user' - >> 'name' ) STORED;
CREATE INDEX idx_user_name ON orders(user_name);
CREATE INDEX idx_os ON devices USING gin ((device_info- > 'os' ));
CREATE INDEX idx_app ON devices USING gin ((device_info- > 'app' ));
CREATE INDEX idx_device_combo ON devices USING gin ((device_info- > 'os' ), (device_info- > 'app' ));
第二个索引大小只有第一个的 60%,查询时能同时命中两个条件。金仓的 JSONB 索引有个特性:支持部分索引。比如只给 Android 设备建索引:
CREATE INDEX idx_android_users ON users USING gin ((profile- > 'device' )) WHERE profile- >> 'os_type' = 'Android' ;
2. 时序数据的老化策略 时序数据最大的特点是'越新的越热,越旧的越冷'。金仓的分区表很好用,但自动老化需要自己配置:
CREATE TABLE transactions (
trans_id BIGSERIAL,
user_id BIGINT ,
amount NUMERIC (10 ,2 ),
trans_time TIMESTAMPTZ NOT NULL
) PARTITION BY RANGE (trans_time);
CREATE OR REPLACE PROCEDURE create_transaction_partitions() LANGUAGE plpgsql AS $$
DECLARE start_date DATE := CURRENT_DATE ; i INT ;
BEGIN
FOR i IN 0. .30 LOOP
DECLARE part_date DATE := start_date + i; part_name TEXT := 'trans_' || to_char(part_date, 'YYYYMMDD' );
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE tablename = part_name) THEN
EXECUTE format('CREATE TABLE %I PARTITION OF transactions FOR VALUES FROM (%L) TO (%L) WITH (fillfactor=95)' , part_name, part_date, part_date + 1 );
END IF;
END ;
END LOOP;
END ; $$;
CREATE OR REPLACE PROCEDURE drop_old_partitions(retention_days INT DEFAULT 90 ) LANGUAGE plpgsql AS $$
DECLARE old_date DATE := CURRENT_DATE - retention_days; part_record RECORD;
BEGIN
FOR part_record IN SELECT inhrelid::regclass as part_name FROM pg_inherits JOIN pg_class ON inhrelid = oid WHERE inhparent = 'transactions' ::regclass AND relname ~ '^trans_\d{8}$' AND substring (relname from 'trans_(\d{4})(\d{2})(\d{2})' )::DATE < old_date LOOP
EXECUTE format('ALTER TABLE transactions DETACH PARTITION %s' , part_record.part_name);
EXECUTE format('DROP TABLE %s' , part_record.part_name);
RAISE NOTICE 'Dropped partition: %' , part_record.part_name;
END LOOP;
END ; $$;
我们设置的是每天凌晨 2 点跑这两个存储过程,保证了永远有未来 30 天的空分区等着,90 天前的数据自动清理,业务完全无感知。
3. 混合负载的资源隔离 HTAP 听起来美好,但分析查询把交易拖垮的事情太常见。金仓的资源组功能是我们的救星:
CREATE RESOURCE GROUP oltp_group WITH ( concurrency = 100 , cpu_rate_limit = 70 , memory_limit = '4GB' , io_priority = 'HIGH' );
CREATE RESOURCE GROUP olap_group WITH ( concurrency = 20 , cpu_rate_limit = 30 , memory_limit = '8GB' , io_priority = 'LOW' );
ALTER USER app_user SET resource_group = 'oltp_group' ;
ALTER USER bi_user SET resource_group = 'olap_group' ;
CREATE OR REPLACE FUNCTION assign_resource_group() RETURNS void LANGUAGE plpgsql AS $$
BEGIN
IF current_query() LIKE 'INSERT%' OR current_query() LIKE 'UPDATE%' OR current_query() LIKE 'DELETE%' OR (current_query() LIKE 'SELECT%' AND current_query() ~ 'WHERE.*=.*' ) THEN
SET LOCAL resource_group = 'oltp_group' ;
ELSIF current_query() LIKE 'SELECT%' AND (current_query() LIKE '%GROUP BY%' OR current_query() LIKE '%WINDOW%' OR current_query() LIKE '%PARTITION%' ) THEN
SET LOCAL resource_group = 'olap_group' ;
END IF;
END ; $$;
实测效果:在未做资源隔离时,一个大的分析查询能让交易响应时间从 5ms 飙升到 200ms。做了隔离后,分析查询可能会慢点(从 2 秒变成 3 秒),但交易响应时间始终稳定在 10ms 以内。
四、迁移实战:从'拆'到'合'的平滑过渡 我们那个项目是从 Oracle 迁移过来的。客户最担心两件事:1)业务代码要重写多少?2)性能会不会下降?
金仓的 Oracle 兼容模式确实省了不少事。我们统计过,大概 85% 的存储过程可以直接跑,只有 15% 需要调整。主要调整点集中在:
Oracle 特有的伪列(ROWNUM 改成 ROW_NUMBER())
日期函数(SYSDATE 改成 CURRENT_TIMESTAMP)
一些特殊语法((+) 外连接改成标准 SQL)
但更重要的是数据模型的重构。原来在 Oracle 里,各种数据是分散在不同表甚至不同实例里的。迁移到金仓,我们趁机做了'数据融合':
CREATE TABLE users ( user_id NUMBER, name VARCHAR2(100 ), id_card VARCHAR2(20 ) );
CREATE TABLE user_ext ( user_id NUMBER, preferences CLOB , device_info CLOB );
CREATE TABLE user_address ( user_id NUMBER, lng NUMBER, lat NUMBER );
CREATE TABLE users (
user_id BIGINT PRIMARY KEY ,
name VARCHAR (100 ),
id_card VARCHAR (20 ),
preferences JSONB,
device_info JSONB,
location GEOMETRY(Point, 4490 )
) PARTITION BY HASH (user_id);
ALTER TABLE users ADD COLUMN province VARCHAR (20 ) GENERATED ALWAYS AS (preferences- >> 'province' ) STORED;
CREATE INDEX idx_users_combo ON users USING btree (province, (device_info- >> 'os_type' ));
迁移过程我们用了金仓的 KFS 工具,支持在线迁移,业务停机时间只有 2 小时(全库 20TB 数据)。迁移后效果:
存储空间:减少 35%(JSONB 压缩 + 列存储)
复杂查询:平均提速 4-8 倍
代码量:减少 60% 的数据访问层代码
五、运维监控:让'一库'好管是关键 功能再强,不好管也是白搭。金仓的监控体系我们觉得设计得很'DBA 友好'。
1. 性能洞察
SELECT tablename, (jsonb_object_keys(jsonb_fields)- >> 'key' ) as json_key, COUNT (* ) as frequency, AVG (LENGTH(jsonb_fields- >> key)) as avg_length
FROM ( SELECT tablename, jsonb_object_keys(device_info) as key, device_info FROM users WHERE device_info IS NOT NULL ) t
GROUP BY 1 , 2 ORDER BY 3 DESC LIMIT 10 ;
SELECT DATE_TRUNC('hour' , query_time) as hour ,
CASE WHEN query_text LIKE '%WHERE transaction_time > NOW() - interval%' THEN 'recent_data' WHEN query_text LIKE '%WHERE transaction_time < %' THEN 'historical_data' ELSE 'other' END as query_type,
COUNT (* ) as query_count, AVG (execution_time) as avg_time
FROM query_history WHERE table_name = 'transactions'
GROUP BY 1 , 2 ORDER BY 1 DESC ;
2. 智能调优建议
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM users WHERE preferences- >> 'city' = '北京' AND device_info- >> 'model' = 'iPhone' ;
输出会包含:建议 1:考虑在 (preferences->>'city', device_info->>'model') 上创建复合索引;建议 2:city 字段基数低,考虑使用位图索引;建议 3:该查询常与时间范围组合,考虑按时间分区。
我们根据建议做了索引优化,一个核心查询从 1200ms 降到了 45ms。
六、思考:融合数据库的边界在哪里? 用了一年多金仓,我们也在思考'一库多能'的边界。目前看:
混合事务分析(HTAP)需求明显的,比如实时风控
数据结构多样但关联紧密的,比如用户画像
希望简化技术栈的中小型团队
纯粹的全文检索(Elasticsearch 还是更强)
超大规模图计算(Neo4j/JanusGraph 的算法更丰富)
海量时序数据(InfluxDB 的压缩率更高)
但金仓聪明的地方在于,它不追求'万能',而是在'企业级核心场景'上做到极致。银行、政务、能源这些领域,需要的不是某个单点能力特别强,而是稳定、可靠、易运维。金仓抓住了这个痛点。
写在最后 '融合数据库'不是新概念,但金仓的实践让我看到了国产数据库的务实思考。它没有盲目追新潮,而是在企业真实需求和技术可行性之间找到了平衡点。
当然也不是没槽点。比如社区版功能限制多,企业版价格不便宜;有些新特性的文档还不够详细,得自己摸索。但整体来说,金仓 KingbaseES 的'一库多能'思路,确实为很多企业提供了一条务实的数据架构演进路径。
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online