ClickHouse是什么?列式数据库架构与分析型业务应用场景

如果你做过报表或数据分析,一定有过这样的经历:一张几亿行的行为日志表,想按天、按渠道做个聚合统计,MySQL 跑了几十秒甚至几分钟才出结果,而且稍微多几个查询,整个库就被拖慢,影响线上业务。这类"扫描海量数据、做聚合分析"的需求,本来就不适合行式存储的 OLTP 数据库。ClickHouse 正是为这个场景而生的。

这篇文章讲清楚 ClickHouse 是什么、为什么它分析快、MergeTree 系列引擎大致是怎么回事、它和 MySQL 的定位差异,以及在什么业务里该用它、什么业务里千万别用。文中涉及具体引擎和参数时给出通用说明,实际行为以官方文档和自己环境的版本为准,不编造具体的性能数字。

什么是 ClickHouse

ClickHouse 是一个开源的列式存储数据库,最初由俄罗斯的团队为网络分析场景开发,后来开源并被广泛用于实时数据分析。它的定位是 OLAP(在线分析处理),核心能力是"对海量数据做快速的聚合查询"。注意这里的重点是"聚合":它擅长把几亿行数据按维度分组求和、计数、求平均,而不是像 MySQL 那样针对单行做高频的增删改查。

理解 ClickHouse,最关键的一点是分清 OLTP 和 OLAP。OLTP(在线事务处理)是 MySQL 这类数据库的强项,特点是单行读写频繁、事务强、并发高、数据量相对可控。OLAP 则是分析场景,特点是批量写入、复杂聚合查询、数据量大、单次查询扫描很多行但返回很少。ClickHouse 是为后者优化的,它的很多设计取舍都和 OLTP 相反。

为什么列式存储这么快

列式存储是 ClickHouse 快的根本原因。行式数据库把一行记录的所有列连续存放,读一行的所有字段很高效;列式数据库把同一列的所有值连续存放,读某一列的全部值很高效。这两种布局的差异在分析场景里被迅速放大。

分析查询通常只涉及少数几列,比如"按天统计订单金额"只用到日期和金额两列。如果是行式存储,数据库必须把每一行都读进来,再从每行里挑出这两列,其他列白白读了。而列式存储只需要读这两列的数据,磁盘 IO 量可能只有行式的十几分之一。数据越宽、查询涉及的列越少,列式存储的优势越明显。

列式存储还带来几个额外好处。同一列的数据类型相同、取值相近,压缩率非常高,常见的压缩算法能把存储空间压到原来的几分之一到十几分之一,进一步减少 IO。同时,列式数据便于做向量化执行——一次处理一批值,而不是一行一行地处理,能更好地利用 CPU 的流水线和缓存。

对比维度 行式存储(MySQL) 列式存储(ClickHouse)
数据布局 按行连续存放 按列连续存放
擅长操作 单行读写、事务 大范围扫描、聚合
分析查询 IO 需要读整行 只读涉及的列
压缩效率 一般 很高
更新单行 高效 低效(不擅长)
典型场景 交易、订单、用户 报表、日志分析、埋点

向量化执行

列存让数据按列连续,CPU 就可以用 SIMD 之类的指令一次处理多个值,而不是逐个循环。加上列存天然适合批量处理,ClickHouse 在扫描和聚合时能跑满 CPU,这也是它比传统行式数据库快一个数量级的原因之一。向量化不代表它适合单行操作,恰恰相反,它的优势建立在"批量处理大量行"之上。

MergeTree 系列引擎

ClickHouse 有几十种表引擎,最核心、最常用的是 MergeTree 家族。简单理解:MergeTree 把数据按列存成一个个数据块(part),后台会不断把小的 part 合并成大的 part,这也是它名字的由来。

MergeTree 的基本结构

建表时可以指定几个关键要素:排序键(ORDER BY)、分区键(PARTITION BY)和主键(PRIMARY KEY,通常和排序键一致)。排序键决定数据在 part 内如何有序排列,主键索引基于排序键构建稀疏索引,分区键决定数据按什么划分到不同的分区目录。查询时,ClickHouse 先按分区裁剪,再靠稀疏索引定位数据块,尽量少读数据。

-- 一个典型的行为日志表
CREATE TABLE events (
  event_date  Date,
  event_time  DateTime,
  user_id     UInt64,
  channel     LowCardinality(String),
  event_type  String,
  amount      Decimal(10, 2)
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, user_id, event_type);

选择分区键和排序键是 ClickHouse 表设计的核心。分区键常用日期(比如按月或按天),便于分区裁剪和按分区删除历史数据;排序键要把最常用的过滤条件放前面,因为稀疏索引只能高效命中排序键的前缀。这里的原则和 MySQL 联合索引的"最左前缀"有相似之处。

常见变体

MergeTree 家族常见的几个变体各自解决一类问题。

引擎 特点 适用场景
MergeTree 基础引擎 通用追加写入场景
ReplacingMergeTree 合并时按排序键去重 需要最终去重的明细表
SummingMergeTree 合并时对数值列求和 预聚合指标表
AggregatingMergeTree 合并时按聚合函数合并 更复杂的预聚合
CollapsingMergeTree 按标记列折叠行 需要记录状态变更
Distributed 分布式表,分片查询 多节点集群

需要提醒的是,ReplacingMergeTree 和 SummingMergeTree 的去重、求和都发生在后台合并时,并不是查询时立刻生效,合并时机由 ClickHouse 决定。如果查询必须严格去重或严格求和,往往要在查询里加 FINAL 或自己做聚合,而 FINAL 有性能代价。这些细节在实际使用中要特别注意,不能想当然地认为"写进去就已经去重了"。

和 MySQL 的定位差异

很多人会问:"我有 MySQL 了,还要 ClickHouse 干什么?"答案不是替代,而是分工。两者解决的问题不一样,通常是搭配使用的。

维度 MySQL ClickHouse
定位 OLTP,事务处理 OLAP,分析处理
数据写入 高频单行增删改 批量导入,少更新
事务 完整 ACID 弱事务,不适合强一致业务
并发 高并发短查询 较低并发、复杂聚合
JOIN 支持较好,适合小表关联 支持但大表 JOIN 性能有限
数据更新 直接 UPDATE/DELETE 用 ALTER 或重建,代价较大
典型用途 订单、账户、业务库 报表、行为分析、指标看板

一个常见的架构是:MySQL 继续承载业务交易,同时把业务数据通过 binlog 或定时任务同步到 ClickHouse,用 ClickHouse 来做报表和实时分析。这样既不影响线上交易的稳定,又能让分析查询跑得飞快。

适用与不适用的场景

ClickHouse 在合适的场景里非常给力,在不合适的场景里则会让人失望。

适合的场景

大宽表的聚合分析是它的主场。比如用户行为分析——几亿条埋点数据,按天、按渠道、按页面做 UV、PV、转化率统计;再比如日志分析——把 Nginx 或应用的日志导入,做关键字检索和趋势统计;还有实时报表和 BI 看板,把业务指标预聚合后供前端展示。这些场景的共同点是数据量大、写入是追加式批量、查询以聚合为主、对单行更新的需求很少。

不适合的场景

高频点更新是首当其冲的禁区。ClickHouse 不擅长频繁地 UPDATE 和 DELETE 单行,虽然较新版本支持了这类操作,但代价较大。强事务也不适合,它不能像 MySQL 那样提供完整的 ACID 保证。此外,大表的复杂 JOIN 性能确实有限,如果业务需要频繁做大表关联,ClickHouse 未必是好选择,可能需要先在数据导入阶段就打成宽表。高并发点查(大量用户同时查单条记录)也不是它的强项,那是 MySQL 或 Redis 的地盘。

业务需求 是否适合 ClickHouse 建议
海量日志聚合统计 适合 主推场景
用户行为与转化分析 适合 主推场景
BI 报表与看板 适合 常配合预聚合
高频单行更新 不适合 用 MySQL
强事务交易 不适合 用 MySQL
大表频繁 JOIN 需谨慎 先打宽表或改造
高并发单点查询 不适合 用 MySQL 或缓存

资源规划

ClickHouse 对资源的需求和 MySQL 有明显差异,规划时要区别对待。

CPU 方面,ClickHouse 非常"能吃"多核,向量化执行和并行扫描都依赖多核。分析负载下,核心越多通常越好,8 核以上是比较常见的起点,重负载场景用 16 核甚至更多。它不太依赖单核高频,更看重核心总数。

内存方面,聚合、排序和 JOIN 都会大量用内存,内存不足时查询会失败(而不是像 MySQL 那样变慢),常见的报错就是内存超限。经验上,分析型负载下内存要尽量充足,宁可多配。要重点关注 max_memory_usage(单个查询的内存上限)等参数,避免一个失控的查询吃光整机内存。

磁盘方面,因为大量顺序读写和大范围扫描,NVMe SSD 几乎是标配,机械盘会严重拖慢查询。同时 ClickHouse 的压缩率虽高,但数据量本身就大,容量要按增长预留。副本和高可用通常靠多副本加 ZooKeeper 或 ClickHouse Keeper 来实现。

# 在 RHEL/CentOS/Rocky 上安装的示意(版本和源以官方文档为准)
sudo dnf install -y clickhouse-server clickhouse-client

# 在 Debian/Ubuntu 上
sudo apt-get update
sudo apt-get install -y clickhouse-server clickhouse-client

# 连接并查看基本状态
clickhouse-client --query "SELECT version()"
clickhouse-client --query "SHOW DATABASES"

风险提示:安装和初始化会创建数据目录(通常 /var/lib/clickhouse),卸载或清空该目录会丢失全部数据,操作前必须确认已备份。修改配置文件后重启服务属于高风险动作,务必在维护窗口进行。

常见问题

ClickHouse 能替代 MySQL 吗?

不能。它是分析型数据库,不擅长高频事务和单行更新。正确做法是让 MySQL 继续承载业务交易,ClickHouse 专门做分析,两者分工配合。

为什么插入很快,更新却很慢?

因为它的存储结构是为批量追加设计的,数据按列存成 part 并靠后台合并维护。单行更新需要额外处理,代价很大。更新频繁的数据不适合放 ClickHouse。

ReplacingMergeTree 会立刻去重吗?

不会。去重发生在后台合并时,时机不确定。查询要严格去重一般要用 FINAL 或自行聚合,这会增加开销。

数据怎么从 MySQL 同步过去?

常见做法是解析 binlog 增量同步,或者定时批量导出导入。同步链路要考虑幂等和延迟,避免重复或丢失。

单机 ClickHouse 够用吗?

中小规模分析场景单机加定期备份可以先用。数据量或并发上来后,再考虑多副本和分片集群,集群会引入 ZooKeeper/Keeper 和分布式表的运维复杂度。

总结

  • ClickHouse 是面向 OLAP 的列式数据库,核心优势是对海量数据做快速的聚合分析。
  • 列式存储只读用到的列、压缩率高、支持向量化执行,这是它快于行式数据库的根本原因。
  • MergeTree 家族是最常用的引擎,排序键、分区键的设计决定了查询效率,去重求和类引擎的生效时机在后台合并。
  • 它和 MySQL 是分工关系:MySQL 管交易,ClickHouse 管分析,常见架构是用同步把数据喂给 ClickHouse。
  • 适合日志、行为分析、报表和宽表聚合;不适合高频点更新、强事务和频繁的大表 JOIN。
  • 资源规划上重多核 CPU、大内存和 NVMe 磁盘,内存不足会直接导致查询失败而非变慢。