月底报表又把库拖垮了?聊聊金仓数据库KES的列存储和真本事

前言

先问个扎心的问题。
你们的数据库,是不是平时岁月静好,一到月底就各种慢?财务要出报表,运营要拉数据,几条大SQL怼进去,整库跟着遭殃。我就见过有人被逼得没辙,专门再买套分析库,或者把跑批全挪到半夜,靠熬夜解决问题。

慢的根子,很多时候不在SQL写得多烂,在存储方式上。

行存储这东西,天生是给交易场景设计的。你让它去跑分析,等于让轿车去拉货。能拉吗?能。累不累?累。金仓数据库KES在行存之外做了原生的列存储,再加上混合负载、高可用、语法兼容一整套东西。这篇就从列存切入,把这些能力一个个捋一遍。

行存和列存,差的不是一点半点

原理其实不复杂。

行存,一整行数据挨着放。查某一行,一次IO基本搞定,插入更新也利索。但你反过来想想:一张一百多列的明细表,你就统计三列,数据库得把整行都读上来。剩下那九十几列,白读。

列存正好倒过来,同一列的值堆一块儿。姓名跟姓名挨着,金额跟金额挨着。做聚合的时候,只碰要用的那几列,别的列压根不加载。而且同一列数据类型一样、重复的又多,压缩起来跟玩似的,空间和扫描量一起往下掉。

列个表对比下,懒得看字的直接扫这张:

对比维度 行存储 列存储
数据怎么放 整行连续 同列的值连续
单行读写 快 慢,要跨列拼
宽表聚合 吃亏 占优
压缩 一般 好,同列类型一致
高频更新 适合 不适合
典型场景 交易、订单 报表、统计

说白了,行存是为"改一行"生的,列存是为"算一列"生的,谁也替不了谁。所以真正值钱的能力是,一个库里两种都给你。

上代码:在KES里建张列存表

从V8系列起KES就支持原生列存表了。建表没什么花活,就多个表级参数(拿V8R6举例):

sql 复制代码
-- ksql -h 127.0.0.1 -p 54321 -U system -d test

CREATE TABLE sales_detail_col (
    order_id    BIGINT,
    cust_id     BIGINT,
    region      VARCHAR(32),
    product_id  INT,
    sale_date   DATE,
    quantity    INT,
    amount      NUMERIC(12,2)
) WITH (orientation = column);

看到没,就 orientation = column 这一句。然后拿同样的结构建张普通行存表,两边灌一样的数据,跑个月度汇总:

sql 复制代码
SELECT DATE_TRUNC('month', sale_date) AS mon,
       SUM(amount)                    AS total_amt
FROM sales_detail_col
WHERE sale_date >= DATE '2026-01-01'
GROUP BY 1
ORDER BY 1;

之前在测试机上随手灌过几百万行试过一次,这种只取两列的聚合,列存快得很明显,量级上就是几倍的差距。具体数字记不清了,也不打算瞎编一个,反正快慢跟你表的宽度、取几列、数据重复度都挂钩。想上生产的话,先拿自己的数据压一遍,别拿别人的结论当圣旨。

再说点底层的东西。搞懂了这个,好多所谓的"坑"回头看都是特性。

KES列存在磁盘上是按CU(压缩单元)组织的。一次写入最多攒六万行,打成一捆,不够六万也是一捆,超了就再来一捆。CU只能追加着写,删除是打标记,更新等于把旧的标记掉、再追加条新的。所以你拿列存表去跑高频小更新,纯属给自己找不痛快。

那零星插入、偶尔改几条怎么办?直接进CU的话,会攒出一堆碎小捆,扫描的时候全是累赘。KES的招儿是配了张DELTA表,小批量的写和改先搁DELTA里,按行存的路子操作,攒够了再合并进CU。相当于给列存加了个缓冲间,挺聪明的设计。

所以选型口诀特简单:追加写为主、做聚合的明细事实表,列存,闭眼上。订单、账务这种一行一行改的,行存,别犹豫。选错场景回头骂数据库,那真不赖人家。

一套库跑两种活,这才是KES的本事

列存把分析查询提速的问题解了,但现实里的麻烦是,交易和分析往往同时来。中午下单高峰,下午运营拉数,你躲不开的。

KES的思路是行存、列存一个实例里共存。交易表行存,事实表列存,各玩各的,应用侧不用维护两套库、两套框架,省心。

这之上还有几块能力得点下名。

并行查询。大表扫描、聚合、连接这种重活,拆给多个worker一起干。配上列存的向量化执行(一批数据一把算,不是一行一行磨),提速是叠加生效的,不是简单相加。

分区。按时间做范围分区几乎是报表大表的标配,查最近三个月,老分区直接裁掉,再叠加列存压缩,数据量再大也稳。

能力归拢成一张表:

能力域 有啥 干嘛用
存储引擎 行存、列存混用 交易分析同库跑
查询执行 并行查询、向量化 大表聚合提速
表级能力 分区表、各种索引 分区裁剪省IO
高可用 主备、自动切换、读写分离 7×24业务
备份恢复 物理备份、逻辑备份 灾备合规
兼容迁移 Oracle/MySQL等兼容模式、KDTS 老系统搬迁
安全 三员分立、国密、审计 等保合规

运维那点事:集群和备份

性能聊完了,说点运维关心的。毕竟系统上线之后,天天陪着它的是运维同学。

KES高可用走主备流复制,一主多备。守护组件盯着主库心跳,主库真趴了,自动把备库提成新主,应用重连就行。提哪个备、等不等数据追平,策略都能配,这块可以按业务容忍度细调。

读写分离是现成的。备机本来就只读,把报表查询引到备机上去,主库专心跑交易。前面说的月底跑批拖垮交易库,这一招能解一大半。

日常用得最多的命令,贴出来备忘:

bash 复制代码
# 集群启停、看状态
./sys_monitor.sh start
./sys_monitor.sh status
./sys_monitor.sh stop

# 物理备份,先改好 sys_backup.conf
./sys_backup.sh init      # 初始化备份环境
./sys_backup.sh backup    # 跑一次物理备份

再送个小技巧,排查的时候特别好用。分不清某台机器是主还是备?看数据目录里有没有standby.signal这个文件。有,备库。没有,主库。比登进库查一圈快多了,谁用谁知道。

搬家方便吗:聊聊兼容性

国产化替换,最疼的不是装库,是把跑在别的数据库上的老应用挪过来。改代码才是大头。

KES的路子是兼容模式,Oracle的、MySQL的都有,初始化实例的时候选定。选了Oracle模式,好多老SQL真不用改:

sql 复制代码
-- 下面这些Oracle风格的,直接跑
SELECT SYSDATE FROM DUAL;

SELECT ROWNUM, t.cust_name
FROM customers t
WHERE t.create_date >= TO_DATE('2026-01-01', 'YYYY-MM-DD')
  AND ROWNUM <= 100;

SELECT NVL(region, '未知') AS region, COUNT(*)
FROM sales_detail
GROUP BY NVL(region, '未知');

-- 老系统常见的 (+) 外连接
SELECT o.order_id, c.cust_name
FROM orders o, customers c
WHERE o.cust_id = c.cust_id(+);

ROWNUM、DUAL、TO_DATE、NVL、(+),连存储过程里那套PL/SQL写法都接得住。配套还有KDTS迁移工具,搬结构、搬数据、出评估报告,手工活省了一截。

不过有个坑必须提前说:兼容模式是实例级的,初始化那会儿就得定下来。库建完了想从Oracle模式换MySQL模式?基本等于推倒重来。所以动手前先想清楚业务从哪迁,别建完库才发现选错了。

安全,顺嘴提两句

行业客户对安全的执念不比性能小,这段就简单说说。

KES安全版有三员分立,系统管理、安全管理、审计管理拆成三个角色,互相独立,谁也别想一手遮天。过等保测评的时候,这套是实打实的加分项。

国密也齐,SM2、SM3、SM4都有落地:传输加密、口令存储、数据加密,各管各的。审计能细到DDL、DML级别,谁几点动了哪张表,事后查得明明白白。

这块不细展开了,各行业版本功能有差异,拿自己的合规清单跟厂商一条条对就行。

最后啰嗦几句

落到实际选型,给几条大实话。

列存看场景上。宽表、追加写、聚合统计,三样占齐,闭眼上;高频单行更新的表就别凑热闹了,行存才是它家。

混搭性价比最高。交易表行存、事实表列存,读写分离把报表引到备机,一套KES全搞定,别急着上两套库。

迁移先把兼容模式定死。初始化那一刻的选择,决定后面应用改造的工作量。先拿KDTS跑个评估,心里有数再动。

最后一句,任何性能结论都自己压一遍。数据分布不同、列宽不同、并发不同,测出来天差地别。自己的业务数据,才是唯一靠谱的裁判。

工具是死的,业务是活的。列存放对位置,集群慢慢调,兼容模式定在最前头,KES这套能力才真算替你干活。就说这么多,有问题评论区聊。

相关推荐
Juicedata1 小时前
面向 EB 级 AI 存储:JuiceFS 企业版架构演进
数据库·人工智能·架构
数据库小学妹1 小时前
MySQL表碎片与 OPTIMIZE TABLE:空间回收的代价与边界
数据库·后端·mysql
java_logo1 小时前
Docker 部署 Hue:轻松搭建数据库与数据仓库 SQL 查询平台
数据库·数据仓库·sql·docker·hue·部署教程·轩辕镜像
Davina_yu1 小时前
1、count(*)、count(1) 和 count(单个字段) 的区别
数据库
锦衣夜行?1 小时前
Oracle 数据库安装失败清理残留步骤
数据库·oracle
时间售卖铺1 小时前
MySQL 表的约束
运维·数据库·mysql·云原生
一条泥憨鱼1 小时前
【Redis | 黑马点评】基于Redis的消息队列 | stream消息队列 源码解读
java·数据库·redis·缓存·lua
CodeGL1 小时前
9、Python基础之IO编程
开发语言·数据库·python
每天一道题1 小时前
Redis 缓存为什么会出问题?穿透、击穿、雪崩与缓存一致性
数据库·redis·缓存