如果你做过报表或数据分析,一定有过这样的经历:一张几亿行的行为日志表,想按天、按渠道做个聚合统计,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 磁盘,内存不足会直接导致查询失败而非变慢。
企业QQ咨询




