ClickHouse 实战:从列式存储到海量数据分析的完整指南

今今晚打老虎2026-10-20数据库⏱ 6min

ClickHouse 实战:从列式存储到海量数据分析的完整指南

当业务数据量达到亿级、查询要求秒级返回时,传统 OLTP 数据库开始力不从心。ClickHouse 以列式存储 + 向量化执行引擎,专为 OLAP 分析场景而生,单机即可支撑每秒数亿行的扫描吞吐。本文从核心原理讲起,完整走一遍落地路径。

一、为什么 ClickHouse 这么快

1.1 列式存储

传统行式存储按行读写,分析查询(只取几列)也要读整行;ClickHouse 按列存储,查询只读取涉及的列,IO 量降低一个数量级:

行式: [id, name, time, value] [id, name, time, value] ...
列式: [id,id,id] [name,name,name] [time,time,time] [value,value,value]

1.2 向量化执行

CPU 一次指令处理一整个数据块(SIMD),而非逐行循环,配合极致的压缩率(列同质性高),磁盘 IO 与 CPU 双双受益。

1.3 数据压缩

列式存储让同列数据高度相似,压缩比可达 10:1 甚至更高,进一步减少 IO。

二、核心表引擎:MergeTree 家族

MergeTree 是 ClickHouse 的基石,理解它的机制就理解了 CH 的用法:

CREATE TABLE events (
    event_date Date,
    event_type String,
    user_id    UInt64,
    amount     Float64
) ENGINE = MergeTree
PARTITION BY toYYYYMM(event_date)   -- 按月分区
ORDER BY (event_date, user_id)      -- 排序键,决定存储顺序

核心机制:

  • 分区:按分区存储,查询可裁剪跳过无关分区;
  • 排序键:数据按 ORDER BY 列有序存储,等于天然索引;
  • 后台合并:小片段后台异步合并成大片段,写入即可查。

三、实战查询:从基础到进阶

3.1 基础聚合

-- 按日统计营收
SELECT event_date, sum(amount) AS revenue
FROM events
WHERE event_date >= '2026-10-01'
GROUP BY event_date
ORDER BY event_date;

3.2 常用函数

-- 去重计数(近似,速度快)
SELECT uniqExact(user_id) FROM events WHERE event_date = '2026-10-20';

-- 分位数(P95 延迟)
SELECT quantile(0.95)(latency_ms) FROM requests WHERE date = today();

-- 漏斗/路径分析
SELECT
    level,
    count() AS users
FROM (
    SELECT user_id,
           multiIf(
               has(groupArray(event_type), 'view') AND has(groupArray(event_type), 'click'), 2,
               has(groupArray(event_type), 'view'), 1, 0) AS level
    FROM events GROUP BY user_id
)
GROUP BY level;

3.3 物化视图:预聚合加速

CREATE MATERIALIZED VIEW daily_stats
ENGINE = SummingMergeTree
ORDER BY (event_date, event_type)
AS
SELECT
    toDate(time) AS event_date,
    event_type,
    count() AS cnt,
    sum(amount) AS total
FROM events
GROUP BY event_date, event_type;

价值:写入时实时增量聚合,查询直接读预聚合结果,亿级明细上的秒级统计不再依赖全量扫描。

四、写入与更新:理解 CH 的数据模型

4.1 批量写入

-- 批量 INSERT 是推荐方式
INSERT INTO events VALUES
  ('2026-10-20', 'view', 1, 10.0),
  ('2026-10-20', 'click', 1, 0.0);
// Go 侧批量写入
batch := ch.Conn.Batch("INSERT INTO events VALUES (?, ?, ?, ?)")
for _, e := range events {
    batch.Append(e.Date, e.Type, e.UserID, e.Amount)
}
batch.Send()

4.2 更新与删除(Mutation)

CH 的 UPDATE/DELETE 是"异步重写"操作,开销大:

ALTER TABLE events DELETE WHERE event_date < '2026-01-01';
ALTER TABLE events UPDATE amount = 0 WHERE event_type = 'refund';

实践:高频更新场景不适合 CH;数据修正用"插入新版本 + 查询取最新"的幂等思路更合适。

五、分布式表:从单机到集群

5.1 集群与分布式表

<!-- config.xml 配置集群 -->
<remote_servers>
    <my_cluster>
        <shard><replica><host>ch-1</host><port>9000</port></replica></shard>
        <shard><replica><host>ch-2</host><port>9000</port></replica></shard>
    </my_cluster>
</remote_servers>
-- 本地表 + 分布式表
CREATE TABLE events_local ... ENGINE = MergeTree ...;
CREATE TABLE events AS events_local
ENGINE = Distributed(my_cluster, default, events_local, rand());

应用只写分布式表,数据自动按分片路由,查询自动聚合各分片结果。

5.2 副本:ReplicatedMergeTree

CREATE TABLE events
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/events', '{replica}')
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, user_id);

Replicated 引擎基于 ZooKeeper/ClickHouse Keeper 自动同步副本,任一节点故障数据不丢。

六、常用运维与监控

clickhouse-client --query "SELECT * FROM system.parts WHERE active=1"   # 查看分区
clickhouse-client --query "SELECT * FROM system.mutations"              # 查看后台任务
clickhouse-client --query "SHOW PROCESSLIST"                            # 查看运行中查询

监控指标:查询延迟 P99、每秒查询数、磁盘 IO、后台 merge 队列长度。

七、适用边界与选型

| 场景 | 推荐 | |------|------| | 亿级日志、埋点分析、漏斗转化 | ClickHouse | | 在线交易、强一致性 OLTP | MySQL/PostgreSQL(不是 CH) | | 多维报表、即席查询 | ClickHouse | | 秒级实时流计算 | 配合 Kafka + 物化视图 |

边界:CH 不适合高频点查(按主键随机查一行)与小事务更新,那是 KV/OLTP 的领域。

结语

ClickHouse 的价值一句话概括:把"等不起的分析"变成"等得起的分析"。列式存储 + 向量化执行 + 预聚合物化视图,三板斧下来,亿级数据的聚合统计可以从分钟级压到毫秒级。落地建议:先从最痛的报表/日志场景开始,用 MergeTree + 物化视图跑通一条真实链路,再逐步把分析查询从 MySQL 迁移过来——你会发现,分析型需求终于不用再"砍需求"了。

读完了?给作者一点支持

本文采用 CC BY 4.0 协议转载 · © 今晚打老虎

评论区加载中…

🔗 相关文章