大家做国产数据库选型或者替代方案评审的时候,我最常被问到的一个问题不是“哪个功能更强”,而是“同样一条 SQL,为什么在 OceanBase 上和 KingbaseES 上跑出来的效果完全不是一个体感”。更直接一点的问法是:金仓 KingbaseES 既不搞分布式存储,也不搞 Paxos 多副本,它凭什么跟 OceanBase 这种明星级产品放在一起比性能?
这个问题其实问到了根子上。很多人以为“性能”是跑分跑出来的,是 CPU 频率和磁盘 IOPS 堆出来的,但实际上对一个数据库来说,性能的底层逻辑是架构。一条 SQL 从客户端发出去,到返回结果集,中间走的是完全不同的两条路:OceanBase 走的是一条为分布式一致性而设计的“协调之路”,KingbaseES 走的是一条把单机硬件压榨到极致的“本地之路”。这两条路没有绝对的优劣,但它们决定了你在什么场景下会感觉到快,在什么场景下会感觉到慢。
这篇文章我想把这两条路掰开揉碎讲清楚,重点放在 KingbaseES 的性能竞争力到底从哪里来。不吹不黑,只说架构逻辑和实际排障时的体感。
1. 为什么 OceanBase 和 KingbaseES 总被放在一起比:目标同向,路线反向
1.1 表面上的共同点:都在做同一件事
先说结论:OceanBase 和 KingbaseES 本质上面对的是同一个市场——关键行业的核心系统数据库替代。金融、运营商、政务、能源,这些行业的客户有一个共同特点:数据量大、并发高、对一致性要求极其苛刻,同时又有很强的国产化替代诉求。
在这个背景下,两家产品经常出现在同一个招标项目的候选名单里,其实是很自然的事。但如果你只看产品宣传页,你会觉得它们什么都像:都支持 SQL,都支持事务,都兼容 Oracle 或 MySQL 的某种语法,都宣称自己在 TPC-C、TPC-H 这类测试里成绩不错。
可一旦把真实的业务 SQL 丢进去跑,差别立刻显现。这个差别不藏在功能列表里,而是藏在架构选择里。
1.2 OceanBase 的路线:原生分布式,先解决“怎么扩展”
OceanBase 从诞生第一天起就是按分布式架构设计的。它的核心思路是:把一份数据分成多个分片,分散到多台服务器上,每台服务器只存一部分数据,然后通过 Paxos 协议保证多副本之间的一致性。
这个架构带来的最大好处是水平扩展能力——业务量涨了,加机器就行,不需要停业务,不需要拆库拆表。但代价也很明显:一条 SQL 一旦涉及跨节点数据,就必须走分布式执行计划,把数据在节点之间搬来搬去。搬数据的过程在数据库内部叫数据重分布(shuffle),这是分布式数据库性能开销的大头。
用一句话概括:OceanBase 的性能竞争力主要来自“用多台机器的资源干一台机器的活”,它的核心复杂度集中在“怎么让一堆机器像一台机器一样工作”。
1.3 KingbaseES 的路线:单机内核深度优化,先解决“单条 SQL 有多快”
KingbaseES 走的是另一个方向。它是基于 PostgreSQL 内核演进的产品,保留了 PostgreSQL 强大的优化器和执行引擎,同时针对国内企业级场景做了大量改造。在默认部署形态下,它是单机架构,主备通过复制同步,数据不需要分片,SQL 不需要跨节点协调。
这意味着一条 SQL 的整个执行过程,从解析、优化到执行,全部发生在一台机器的内存和磁盘之间,没有网络往返,没有协调节点,没有数据重分布。
它的性能竞争力来自两个层面:一是 PostgreSQL 内核本身在单机性能优化上几十年的积累;二是金仓针对国产芯片、国产操作系统做了深度适配,在飞腾、鲲鹏、海光这些平台上能把硬件性能吃得更透。
| 对比维度 | OceanBase | KingbaseES |
|---|---|---|
| 核心架构 | 原生分布式、存储计算分离 | 单机集中式、主备复制 |
| 数据分片 | 自动分片、多副本 | 不分片,依赖硬件纵向扩展 |
| 一致性实现 | Paxos 多副本协议 | 主备同步/异步复制 |
| SQL 执行方式 | 分布式执行计划,可能跨节点重分布数据 | 本地执行计划,单机完成 |
| 扩展方式 | 加节点横向扩展 | 升级硬件或读写分离 |
| 性能优化重点 | 分布式协调、网络开销、负载均衡 | 优化器、缓存、磁盘 IO、并行查询 |
看到这张表你应该明白了:这两家不是谁比谁强的竞争关系,而是选择了完全不同的技术路线。搞清楚这一点,再去讨论“一条 SQL 谁跑得快”才有意义。
2. 一条 SQL 在两条路上的执行路径:从解析到返回结果集的分岔点
我们选一条业务里非常典型的 SQL,走一遍它在两个数据库内部的完整旅程:
SELECT c.cust_name, SUM(o.amount) AS total_amount FROM orders o JOIN customers c ON o.cust_id = c.id WHERE o.create_time >= '2024-01-01' AND o.status = 'PAID' GROUP BY c.cust_name ORDER BY total_amount DESC LIMIT 10;这条 SQL 涉及 JOIN、过滤、分组聚合、排序、分页,算是 OLAP 场景里常见的基本款。两条路线在这条 SQL 上的差异,几乎覆盖了所有关键分岔点。
2.1 分岔点一:语法解析和合法性校验的清单不同
任何数据库收到 SQL 之后,第一步都是语法解析,把文本变成内部语法树。这一步的性能差异其实不大,真正的差异在于“能解析什么”。
OceanBase 在语法兼容上主打 MySQL 和 Oracle 两个模式。KingbaseES 的看家本领是 Oracle 兼容,同时兼容 PostgreSQL 和 MySQL 的常用语法。
这里有一个容易被低估的点:兼容性直接决定了一条 SQL 能不能用最简单的写法跑出最好的计划。举个例子,很多从 Oracle 迁移过来的业务会用CONNECT BY做层次查询,用MERGE INTO做增量更新。如果目标数据库不支持这些语法,你就得改 SQL——而改写之后的 SQL 往往不是性能最优的形态。KingbaseES 在 Oracle 兼容上做得比较深,很多迁移项目里 SQL 可以不做修改直接跑,这一步就省掉了大量改写导致的性能损耗风险。
从我的实际经验来看,在国产数据库迁移项目中,“语法能不能过”只是第一关,“改写后的 SQL 性能会不会劣化”才是第二关,而第二关往往更致命。所以兼容性这个东西,表面上是语法问题,实际上深度影响性能。
2.2 分岔点二:优化器生成执行计划的输入完全不一样
语法解析之后是重头戏——查询优化。优化器的作用是决定“怎么查最快”,它通常基于代价估算(CBO),给每种可能的执行方式算一个预期代价,然后选代价最小的。
OceanBase 的优化器要额外考虑一件事:数据在哪个节点上。如果一张表被分片到了 20 台服务器,那么 JOIN、GROUP BY 这些操作天然就是分布式的。优化器不仅要决定用不用索引、用哪种 JOIN 方式,还要决定数据怎么在节点之间流转——是广播小表,还是重分布大表。这些决策直接决定了 SQL 的网络开销,而网络开销往往比磁盘 IO 更慢、更不可控。
KingbaseES 的优化器不需要考虑跨节点问题。它只需要专注于一件事:选择最优的本地执行路径——走哪个索引、用哪种 JOIN 算法(嵌套循环、哈希连接、归并连接)、是否启用并行、以什么顺序扫描表。
你可能会觉得 KingbaseES 的优化器工作更简单,但“简单”恰恰是优势。一条 SQL 在单机上可能只有几十种执行计划组合,在分布式环境里可能生成上千种——计划空间越大,优化器选到次优计划(甚至坏计划)的概率就越大。单机优化器虽然选择空间小,但每一种选择都是围绕真实代价计算的,稳定性反而更高。
2.3 分岔点三:执行引擎的“搬数据”和“本地算”之争
这是两条路差异最悬殊的地方。
在 OceanBase 上,刚才那条 SQL 如果 orders 表和 customers 表的连接键不在同一个分片键上,执行引擎就必须把两边的数据按连接键值重新打散到所有节点,然后每个节点只算自己那一份,最后汇总。这个“打散—重算—汇总”的流程,每一步都涉及网络传输和节点间同步。数据量小的时候没感觉,数据量上到千万行、亿行,时间几乎全花在搬数据上。
在 KingbaseES 上,整个过程没有一次网络传输:扫描、连接、分组、排序全部在一台机器的内存里完成,最多是多个 CPU 核并行处理不同数据块。
用大白话说:OceanBase 是“叫了一堆人过来一起干活,但每一道工序之间都要交接”;KingbaseES 是“一个全能师傅从头干到尾,中间的半成品不用搬来搬去”。对很多中型规模的数据集来说,后者反而更快。
2.4 分岔点四:执行计划缓存和作用域
两个数据库都会缓存执行计划,避免每次执行 SQL 都重新做优化。但缓存的粒度不一样。
OceanBase 的执行计划缓存要考虑分布式环境下的路由信息、分区信息。如果一张分区表的统计信息发生变化,或者某个节点不可用,执行计划可能需要重新生成。在复杂分布式集群里,执行计划失效是很常见的,而重新生成计划的代价比单机高得多。
KingbaseES 的缓存在这一点上非常省心:它基于 SQL 文本做计划缓存,同样的 SQL 只要参数不同,直接走通用计划。虽然偶尔会遇到“通用计划不如定制计划”的经典问题,但整体上对 OLTP 这类以短查询为主的业务非常友好——短查询的执行时间本来就只有毫秒级,省掉优化时间就是实实在在的收益。
我见过不少团队在用分布式数据库跑 OLTP 业务时遇到一个问题:单条 SQL 的并发量很高,每条 SQL 又要花不少时间在计划生成和分布式协调上,导致 CPU 大量消耗在“执行之前的事情”上,而不是真正的数据计算上。而 KingbaseES 这类单机数据库,同样一批短 SQL,CPU 几乎全部花在有效的索引查找和数据返回上。
3. KingbaseES 性能竞争力藏在哪几个关键环节:不只是“PG 套壳”这么简单
很多人一听 KingbaseES 基于 PostgreSQL,就下意识觉得“这不就是改了个名吗”。实际用过就会发现这种判断太粗糙了。金仓确实借了 PG 的底子,但它在性能上的功夫,更多是在 PG 内核的基础上做了针对性的深挖和改造。
3.1 共享缓冲区与本地内存利用:OLTP 短查询的隐形加速器
数据库 90% 以上的性能问题,最后都能归结到内存和磁盘的博弈上。KingbaseES 继承了 PostgreSQL 的共享缓冲区(shared_buffers)机制,同时结合国产服务器的实际内存配置做了调优。
这里面最值得说的是:单机架构让内存命中率可以做到非常稳定。所有热点数据都在这台机器的内存里,不存在“数据在远端节点上要多一次网络读取”的问题。对高并发的订单查询、账户余额查询、流水查询这类业务,只要内存够大,缓存命中率可以长期维持在 95% 以上,查询时间基本就是内存读的速度。
很多从 Oracle 迁移到国产库的团队,最不适应的就是“怎么还要关心 shared_buffers 配多大”。这个参数确实需要调,但调好之后的收益非常直接。根据金仓官方文档的建议,shared_buffers 一般设置为物理内存的 25% 左右,再配合操作系统层面的 page cache,实际可用缓存往往能覆盖整张热表。
对比 OceanBase 的架构:它的存储引擎用 LSM-Tree,写入路径经过内存的 memtable,读的时候要先查内存再查磁盘,同时还要走多副本的一致性协议。写入吞吐确实强,但读路径上的环节比单机数据库多,这是分布式架构无法回避的额外开销。
3.2 存储引擎和索引设计:经典路线的稳定红利
KingbaseES 的存储引擎是堆表 + MVCC,索引默认是 B-tree,同时支持 Hash、GiST、SP-GiST、GIN、BRIN 等多种索引类型。这套组合在 PostgreSQL 社区里被验证了二十多年,属于数据库领域的“经典款”——不花哨,但该有的都有了。
对实际业务来说,索引带来的性能提升往往比存储引擎本身的差异更直接。比如:
- 一个等值查询,走 Hash 索引可能比走 B-tree 更快;
- 一个范围查询,B-tree 是最合适的选择;
- 全文检索或者数组包含这类场景,GIN 索引优势明显;
- 数据量极大但数据的物理顺序与查询条件高度相关的场景,BRIN 索引能以极小的空间代价提供不错的过滤能力。
OceanBase 的存储引擎是 LSM-Tree,它在高并发写入场景下非常能打,但 LSM-Tree 的代价是读放大和空间放大。虽然 OceanBase 做了很多优化(比如分层压缩、bloom filter),但“写优化”和“读优化”之间的跷跷板效应是逃不掉的。
如果你业务里读多写少(绝大多数传统业务都是这个形态),KingbaseES 的经典存储引擎在稳定性和可预测性上更有优势。
3.3 并行查询能力:单机内部的多核利用
很多人有个误区:以为单机数据库只能用一个 CPU 核跑 SQL。KingbaseES 的并行查询机制其实可以调动多个核同时处理一条 SQL。
它的执行模型是:优化器预估 SQL 的代价,超过阈值就启用并行。以刚才那条 GROUP BY 聚合查询为例,KingbaseES 可以这样并行:
- 多个并行 worker 同时扫描 orders 表,各自负责不同的数据块;
- 每个 worker 把符合条件的数据做本地预聚合(partial aggregation);
- 第一步聚合结果提交给 leader 进程,leader 做最终聚合(final aggregation)。
整个过程还是在同一台机器内部,但通过并行把 CPU 多核能力用起来了。对分析型 SQL 来说,并行度配置合理的情况下,性能可以提升数倍。
OceanBase 同样有并行查询能力,但它的并行发生在多台机器之间。并行度更高,但并行任务的调度、数据交换的开销也更大。如果集群规模不够大,或者网络带宽成为瓶颈,分布式的并行不一定比单机并行快。
这里有一个非常实用的工程经验:不要盲目追求高并行度。在 KingbaseES 上,max_parallel_workers_per_gather设置成 2 到 4 往往就能覆盖绝大多数场景,并行度太高反而会因为进程间通信和上下文切换带来额外开销。做压测时,应该从低到高一档一档试,找到拐点。
3.4 Oracle 兼容带来的“迁移后性能不倒退”红利
最后这一点可能是 KingbaseES 在国产数据库阵营里最独特的竞争力——它对 Oracle 的兼容不是停留在语法层面,而是深入到了行为层面。
这个“行为兼容”会直接体现在性能上。举个经典例子:Oracle 里的ROWNUM分页写法,很多国产数据库只支持改写后的LIMIT/OFFSET写法,但改写的执行计划不一定最优。KingbaseES 支持ROWNUM,并且能把它优化成“取到 N 行即停止”的短路执行——比如只取前 10 行,就不会傻傻地把所有符合条件的数据都算完再截断。
再比如NULL语义、字符串拼接规则、隐式类型转换的行为,这些细枝末节的东西如果不兼容,SQL 改写时就会改变原意,最终导致执行计划和性能不可控。KingbaseES 在这些细节上做了大量对齐,让老 Oracle 系统的 SQL 能原封不动地跑出和原来同级别的性能。
从项目实际来看,迁移后性能倒退 80% 的案例,绝大多数不是因为数据库本身慢,而是因为 SQL 被改写后执行计划劣化了。金仓的兼容策略从源头堵住了这个问题。
4. 三个高频场景实测:同样的 SQL,两条路线的表现逻辑
前面讲了架构和原理,这一节用三个具体的场景,带大家看看到底怎么判断一条 SQL 在两条路上会表现出什么差异,以及排障时应该从哪里下手。
4.1 场景一:GROUP BY + JOIN 大查询(慢 SQL 优化的经典题)
业务场景很常见:有个大订单表(几千万行),要按客户维度汇总消费金额。这是慢 SQL 优化里最经典的重度聚合场景。
在 OceanBase 上执行时,如果订单表和客户表的分布键不一致,优化器会生成重分布计划:先把订单表按 cust_id 哈希分发到所有节点,再把客户表按 id 哈希分发。两个表重分布完成之后,每个节点才本地做 JOIN 和 GROUP BY。
在 KingbaseES 上执行时,优化器有两种选择:如果客户表足够小,选择 Hash Join 时会把客户表作为驱动表加载到内存,然后全表扫描订单表,在内存里做连接和聚合;如果两个表都很大,可以启用并行查询,多个 worker 分别扫描订单表的不同部分,本地聚合后汇总。
两条路线的共同点是:聚合的计算量都被分散了。区别在于,OceanBase 分散到机器之间,KingbaseES 分散到 CPU 核之间。网络带宽是 GB 级别,内存带宽是几十 GB 到上百 GB 级别,差了一个数量级。所以对数据量在单机能装下的场景,KingbaseES 的优势非常明显。
这里给一个排查慢 SQL 的实际建议:在 KingbaseES 里用EXPLAIN ANALYZE看执行计划时,重点关注三点——有没有走索引、Hash Join 时哈希表有没有落盘、并行 worker 的实际启动数量是不是和配置一致。这三个点基本覆盖了 80% 的重度聚合查询性能问题。
4.2 场景二:窗口函数 + 排序(ROW_NUMBER 去重取最新)
现在业务里大量用到窗口函数,典型场景是“取每个用户最近一笔订单”。
SELECT * FROM ( SELECT o.*, ROW_NUMBER() OVER (PARTITION BY cust_id ORDER BY create_time DESC) AS rn FROM orders o WHERE o.status = 'PAID' ) t WHERE rn = 1;窗口函数的核心成本在排序。PARTITION BY cust_id ORDER BY create_time DESC意味着要按客户 ID 分组、组内按时间排序。
在分布式架构里,窗口函数的分区键和表的分片键如果不一致,优化器就必须把数据按分区键重新打散到各节点,然后在每个节点上做组内排序。数据重分布的代价在这里会被指数级放大——重分布的时间甚至可能超过排序本身。
在 KingbaseES 上,如果 orders 表在 cust_id 上有索引,优化器可以利用索引的有序性避免物理排序。即使没有索引,单机上做一次全表排序的开销也远小于分布式环境下的“重分布 + 多次排序”。再加上 PostgreSQL 对窗口函数有专门的优化——通过top-N堆排序(heapsort)或者incremental sort避免全量排序——在“只取每组前 N 行”的场景下,实际排序代价比想象中小得多。
这个场景也顺便回应了搜索热词里“sql窗口函数”“sql语句去重”的关注点:去重取最新的本质就是一个分组排序的过程,判断数据库行不行,就看它在分组排序上有没有省力的执行策略。
4.3 场景三:大批量数据导入和去重
最后一个场景其实最能区分架构差异。假设你要一次性往数据库里灌 500 万行订单数据,同时要求数据不能重复(ON CONFLICT DO UPDATE或MERGE INTO语义)。
OceanBase 的 LSM-Tree 存储引擎在这个场景下优势明显:写入先进内存 memtable,批量转储到磁盘,顺序写为主,写放大被控制得比较好。高吞吐导入对分布式数据库来说确实是主场。
KingbaseES 的堆表 + B-tree 在导入时则要面对经典的 B-tree 维护开销:每插入一行都要更新索引,如果索引频繁分裂,还会产生额外写放大。这也是很多人诟病 PG 系数据库“写入慢”的根源。
但这里有一个实践中的反转:单机写入慢,可以通过批量提交和并行导入来弥补。把 500 万行的 INSERT 拆成多个并发任务,每个任务按主键范围分成片段批量插入,同时在导入期间去掉非必要的二级索引(导入后再建),KingbaseES 的实际导入性能完全可以压到业务可接受的范围内。而且导入完成后,数据不需要跨节点再平衡——在 OceanBase 里导入完成后经常还需要做一次数据均衡和 compaction,这又是一个隐性时间成本。
核心思路是:在选型阶段就要明确你的业务是“写一次读一万次”还是“时刻高频写”。如果是前者,KingbaseES 这种单机架构完全扛得住,而且运维简单得多。
5. 选型不是站队:什么业务适合走哪条路
看了这么多对比,如果你问我“OceanBase 和金仓到底选哪个”,我的答案永远是:先回答你自己的业务是什么形态。
拿一张表帮你快速定位:
| 你的业务特征 | 更适合的路线 | 原因 |
|---|---|---|
| 数据量单机装得下(几 TB 以内),但并发很高 | KingbaseES | 单机避免分布式协调开销,短查询快,运维简单 |
| 数据量持续增长,明确超过单机容量上限 | OceanBase | 分布式架构天然支持横向扩展 |
| 业务 SQL 以 JOIN、聚合、复杂分析为主 | KingbaseES | 单机本地执行,无跨节点重分布成本和网络开销 |
| 业务要求极高的写入吞吐(如流水类数据) | OceanBase | LSM-Tree 的写路径更强 |
| 老 Oracle 系统迁移,希望 SQL 少改甚至不改 | KingbaseES | Oracle 兼容深度高,性能不易劣化 |
| 对跨机房容灾、多活有强诉求 | OceanBase | 原生多副本 + Paxos,容灾能力内置 |
| 团队 DBA 数量少,希望运维尽量简单 | KingbaseES | 单机架构排查问题链路短,不需要学分布式运维 |
| 未来几年数据规模有明确的几何级增长预期 | OceanBase | 避免以后拆库拆表的痛苦 |
这个表格不是绝对的,但方向是对的。
另外还要说一个很多人踩过的坑:迁移评估时只看语法兼容,不看执行计划形态。两个数据库都能执行同一条 SQL,不代表执行方式一样。在 Oracle 上走了索引的查询,迁移到另一个库之后,可能因为统计信息、优化器版本、数据分布不同,变成了全表扫描。
所以我的建议是:无论你倾向选哪家,正式立项前先做一轮“真实业务 SQL 全量跑批”——拿生产环境里最重的那 20 到 30 条 SQL,在新库上用真实数据量跑一遍,对比执行计划和响应时间。这一步省不掉,也偷不得懒,它才是选型最有价值的参考依据。
6. 写在最后:抛开“谁更强”,看“谁更合适”
回到标题那个问题:KingbaseES 的性能竞争力从哪来?我的答案是:从“专注”中来。它专注做单机内核的深度优化,专注把 Oracle 兼容做到位,专注让数据库在国产硬件栈上跑得更稳。它没有去追分布式这个热点,而是把一条更传统的路走到了极致。而 OceanBase 的竞争力在于“重构”——用分布式架构重新定义了 SQL 在多机环境下的执行方式。
这两条路没有谁一定优于谁。真实世界里,一个小型系统用 OceanBase 可能根本感受不到分布式的红利,反而被它的复杂度拖累;而一个超大规模系统硬要用 KingbaseES 撑,也很可能卡在单机容量的天花板上。技术选型最忌讳的就是“因为谁名气大就选谁”,更忌讳的是“因为谁便宜就选谁”。
我个人在实际项目中的体感是:大多数企业的核心业务系统,数据量远没到单机装不下的程度,真正让他们痛苦的不是架构不够先进,而是运维太复杂、SQL 跑太慢、出了问题没人能排查。对这类用户来说,KingbaseES 这种“经典单机 + 深度兼容”的路线反而是风险更低的选择。当然,如果你正在设计一个从零开始的、有明确海量数据预期的互联网级系统,OceanBase 的分布式能力就是需要考虑的。
最后再分享一个实用技巧:选型测试的时候,不要只盯着平均响应时间,要看P99 延迟和延迟抖动。分布式数据库在平均表现上往往不差,但在系统负载波动、节点间网络抖动、数据重分布任务并发执行时,P99 延迟会突然变得很难看。单机数据库在这个指标上天然更稳定。而核心交易系统的用户感知,恰恰是由那 1% 的最慢请求决定的。