ClickHouse 工作原理

ClickHouse是一款真正的列式存储向量化执行MPP架构 的OLAP数据库。它的核心设计哲学是:极致地利用所有硬件资源(CPU、内存、磁盘I/O),在最短时间内处理海量数据。


1. 存储引擎(如何高效存放数据)

这是ClickHouse性能的基石,核心在于"列式"与"压缩"。

  • 列式存储:数据按列而非按行连续存放。查询时只需读取涉及的列,大幅减少I/O。同时,同一列的数据类型相同,相邻数据相似度极高,为高效压缩创造了条件。

  • 数据压缩 :默认使用LZ4 算法,压缩比可达1:81:10。数据压缩后,读取的数据量更小,从磁盘传输到内存的速度更快。对于重复值高的列(如枚举类型),还会使用字典编码,将字符串映射为整数再压缩。

  • 数据排序与稀疏索引 :数据在MergeTree引擎中按主键ORDER BY指定的键)严格排序存储。ClickHouse利用这种排序特性,为主键每隔8192行(或index_granularity)创建一个稀疏索引(Primary Index)。

    • 查询过程 :二分查找稀疏索引,快速定位到可能包含数据的granule(颗粒)范围,跳过大量不相关数据块。
  • 数据分区(Partition):支持按日期等维度进行分区。查询时,会利用分区裁剪(Partition Pruning)直接跳过不相关的分区目录。


2. 计算引擎(如何快速处理数据)

读取数据后,计算引擎的核心任务是压榨CPU,这里有两个杀手锏:向量化执行和实时编译。

  • 向量化执行(Vectorization)

    • 传统数据库采用逐行迭代(Volcano模型),每处理一行就要调用一次虚函数,CPU开销巨大。

    • ClickHouse采用批量处理 ,每次从磁盘或内存中读取一批数据(向量),通常是10244096行,放入CPU的SIMD(单指令多数据流) 寄存器。一条CPU指令可同时对向量中的所有数据执行运算(如+>AND)。这种方式极大地提高了CPU缓存命中率,减少了分支预测失败。

  • 实时编译(JIT):将热点查询表达式编译为机器码,消除虚函数调用,进一步释放CPU性能。

  • 聚合哈希表(Hash Table)GROUP BY是核心操作。ClickHouse针对不同数据量,动态选择最优的哈希表实现(如密集哈希、稀疏哈希、平铺哈希),并支持在内存不足时**溢写(Spill)**到磁盘。


3. 分布式架构(如何协同多台机器)

  • MPP + Shared-Nothing :每台服务器独立拥有CPU、内存和磁盘。节点间通过TCP网络传递数据,不共享存储。

  • 分片(Shard) :数据按分片键(如用户ID的哈希值)水平分散到不同节点,实现横向扩展。

  • 副本(Replica) :依赖ZooKeeperClickHouse Keeper管理元数据,实现数据多副本,提供高可用性。

  • 查询分发与聚合

    1. 客户端向集群节点(发起节点即协调者)发送查询。

    2. 协调者将查询拆解,分发到所有相关分片执行。

    3. 各分片完成局部计算,将中间结果返回协调者。

    4. 协调者做最终聚合 (如合并GROUP BY结果)并返回给客户端。


4. MergeTree引擎的内部工作细节

MergeTree是ClickHouse最核心的表引擎,理解它的"合并"过程至关重要。

  • 数据写入(Part) :每次INSERT操作会立刻生成一个新的数据目录(Part) ,而不是修改已有数据。这避免了随机写,转为顺序写,写入速度极快(可达50MB/s-200MB/s)。

  • 后台合并(Background Merge) :如果Part过多,查询时需要打开大量文件,性能下降。后台线程会持续将多个小的Part合并成更大的Part关键点 :合并时才进行去重 (针对ReplacingMergeTree)和数据过期删除 (针对TTL)。

  • 数据不可变性(Immutable) :已生成的Part是只读的。因此,UPDATEDELETE在ClickHouse中是异步的"突变"(Mutation)操作------生成新Part替换旧Part,而非原地更新。


5. 查询执行流程(一条SQL的生命周期)

SELECT city, count() FROM table WHERE date='2026-06-22' GROUP BY city 为例:

  1. 解析与优化:SQL解析为AST(抽象语法树),进行谓词下推、列裁剪等优化。

  2. 分区裁剪 :仅读取date分区。

  3. 索引查找 :利用稀疏索引跳过不匹配的granule

  4. 读取数据 :只读取city列和必要的行号列(标记文件)。

  5. 向量化过滤 :对city列使用SIMD指令进行过滤。

  6. 聚合计算 :构建哈希表(Key为city,Value为count())。

  7. 返回结果:若涉及多分片,执行分布式合并。


6. 适用场景与局限性

优势(极致性能) 局限性(权衡设计)
宽表大宽表扫描性能极佳 高并发点查QPS > 1000)较弱(因稀疏索引,适合1000+行扫描)
数据压缩率极高,节省存储成本 事务支持 弱(无ACID,仅支持原子性INSERT
写入吞吐量极高(每秒百万行) 去重与更新 成本高(依赖ReplacingMergeTree+合并,非实时)
复杂分析函数(窗口函数、漏斗分析)支持好 Join性能受限(右表需全加载内存,大表Join需优化)

总结:一句话概括

ClickHouse利用"列式排序存储 + 稀疏索引"极大减少I/O,再通过"向量化SIMD + JIT编译"榨干CPU,最后使用"异步合并Part"将随机写入转化为高吞吐顺序写入,最终在廉价硬件上实现海量数据的秒级分析查询。