ClickHouse是一款真正的列式存储 、向量化执行 、MPP架构 的OLAP数据库。它的核心设计哲学是:极致地利用所有硬件资源(CPU、内存、磁盘I/O),在最短时间内处理海量数据。
1. 存储引擎(如何高效存放数据)
这是ClickHouse性能的基石,核心在于"列式"与"压缩"。
-
列式存储:数据按列而非按行连续存放。查询时只需读取涉及的列,大幅减少I/O。同时,同一列的数据类型相同,相邻数据相似度极高,为高效压缩创造了条件。
-
数据压缩 :默认使用LZ4 算法,压缩比可达
1:8到1:10。数据压缩后,读取的数据量更小,从磁盘传输到内存的速度更快。对于重复值高的列(如枚举类型),还会使用字典编码,将字符串映射为整数再压缩。 -
数据排序与稀疏索引 :数据在MergeTree引擎中按主键 (
ORDER BY指定的键)严格排序存储。ClickHouse利用这种排序特性,为主键每隔8192行(或index_granularity)创建一个稀疏索引(Primary Index)。- 查询过程 :二分查找稀疏索引,快速定位到可能包含数据的
granule(颗粒)范围,跳过大量不相关数据块。
- 查询过程 :二分查找稀疏索引,快速定位到可能包含数据的
-
数据分区(Partition):支持按日期等维度进行分区。查询时,会利用分区裁剪(Partition Pruning)直接跳过不相关的分区目录。
2. 计算引擎(如何快速处理数据)
读取数据后,计算引擎的核心任务是压榨CPU,这里有两个杀手锏:向量化执行和实时编译。
-
向量化执行(Vectorization):
-
传统数据库采用逐行迭代(Volcano模型),每处理一行就要调用一次虚函数,CPU开销巨大。
-
ClickHouse采用批量处理 ,每次从磁盘或内存中读取一批数据(向量),通常是
1024或4096行,放入CPU的SIMD(单指令多数据流) 寄存器。一条CPU指令可同时对向量中的所有数据执行运算(如+、>、AND)。这种方式极大地提高了CPU缓存命中率,减少了分支预测失败。
-
-
实时编译(JIT):将热点查询表达式编译为机器码,消除虚函数调用,进一步释放CPU性能。
-
聚合哈希表(Hash Table) :
GROUP BY是核心操作。ClickHouse针对不同数据量,动态选择最优的哈希表实现(如密集哈希、稀疏哈希、平铺哈希),并支持在内存不足时**溢写(Spill)**到磁盘。
3. 分布式架构(如何协同多台机器)
-
MPP + Shared-Nothing :每台服务器独立拥有CPU、内存和磁盘。节点间通过TCP网络传递数据,不共享存储。
-
分片(Shard) :数据按分片键(如用户ID的哈希值)水平分散到不同节点,实现横向扩展。
-
副本(Replica) :依赖ZooKeeper 或ClickHouse Keeper管理元数据,实现数据多副本,提供高可用性。
-
查询分发与聚合:
-
客户端向集群节点(发起节点即协调者)发送查询。
-
协调者将查询拆解,分发到所有相关分片执行。
-
各分片完成局部计算,将中间结果返回协调者。
-
协调者做最终聚合 (如合并
GROUP BY结果)并返回给客户端。
-
4. MergeTree引擎的内部工作细节
MergeTree是ClickHouse最核心的表引擎,理解它的"合并"过程至关重要。
-
数据写入(Part) :每次
INSERT操作会立刻生成一个新的数据目录(Part) ,而不是修改已有数据。这避免了随机写,转为顺序写,写入速度极快(可达50MB/s-200MB/s)。 -
后台合并(Background Merge) :如果Part过多,查询时需要打开大量文件,性能下降。后台线程会持续将多个小的
Part合并成更大的Part。关键点 :合并时才进行去重 (针对ReplacingMergeTree)和数据过期删除 (针对TTL)。 -
数据不可变性(Immutable) :已生成的Part是只读的。因此,
UPDATE和DELETE在ClickHouse中是异步的"突变"(Mutation)操作------生成新Part替换旧Part,而非原地更新。
5. 查询执行流程(一条SQL的生命周期)
以 SELECT city, count() FROM table WHERE date='2026-06-22' GROUP BY city 为例:
-
解析与优化:SQL解析为AST(抽象语法树),进行谓词下推、列裁剪等优化。
-
分区裁剪 :仅读取
date分区。 -
索引查找 :利用稀疏索引跳过不匹配的
granule。 -
读取数据 :只读取
city列和必要的行号列(标记文件)。 -
向量化过滤 :对
city列使用SIMD指令进行过滤。 -
聚合计算 :构建哈希表(Key为
city,Value为count())。 -
返回结果:若涉及多分片,执行分布式合并。
6. 适用场景与局限性
| 优势(极致性能) | 局限性(权衡设计) |
|---|---|
| 宽表大宽表扫描性能极佳 | 高并发点查 (QPS > 1000)较弱(因稀疏索引,适合1000+行扫描) |
| 数据压缩率极高,节省存储成本 | 事务支持 弱(无ACID,仅支持原子性INSERT) |
| 写入吞吐量极高(每秒百万行) | 去重与更新 成本高(依赖ReplacingMergeTree+合并,非实时) |
| 复杂分析函数(窗口函数、漏斗分析)支持好 | Join性能受限(右表需全加载内存,大表Join需优化) |
总结:一句话概括
ClickHouse利用"列式排序存储 + 稀疏索引"极大减少I/O,再通过"向量化SIMD + JIT编译"榨干CPU,最后使用"异步合并Part"将随机写入转化为高吞吐顺序写入,最终在廉价硬件上实现海量数据的秒级分析查询。