为什么选择Clickhouse而不是ElasticSearch?
ClickHouse 和 Elasticsearch 都很快,但它们的"快"是针对完全不同的业务场景而言的。
ClickHouse 的快,体现在对海量数据进行大规模聚合分析时的高吞吐和低延迟;而 Elasticsearch 的快,则体现在对大量文本进行全文检索时的快速响应。
# 1、核心差异对比
| 对比维度 | ClickHouse | Elasticsearch |
|---|---|---|
| 核心定位 | OLAP 分析型数据库,专为海量数据(PB级)的聚合、分析查询设计。 | 分布式搜索和分析引擎,基于 Lucene 构建,专为全文检索和日志分析设计。 |
| 存储模型 | 列式存储。只读取查询涉及的列,I/O效率极高,压缩比高。 | 行式存储为主(底层 Lucene 也支持列存 Doc Values)。查询时通常需要读取整行,在海量数据分析场景下 I/O 开销较大。 |
| 数据索引 | 主键稀疏索引 + 跳数索引。数据按主键排序存储,通过索引快速跳过不相关的数据块,适用于范围查询和聚合。 | 倒排索引。对每个字段分词后建立词项到文档的映射,专为关键词匹配和全文搜索优化,查询速度极快。 |
| 写入机制 | 实时写入磁盘。每次 INSERT 会生成一个新的数据分片(DataPart),直接落盘,写入性能极高。 | 近实时(NRT)。数据先写入内存,定期刷新(Refresh)到磁盘的 Segment 后才可被搜索,存在短暂延迟。 |
| 查询执行 | 向量化执行 + MPP架构。利用 SIMD 指令批量处理数据,查询会被并行分发到所有分片执行,充分利用多核 CPU 和集群算力。 | 通用的搜索模式。通常先查询倒排索引获取 Top N 的文档 ID,再回查存储获取明细数据。 |
| 分布式架构 | Multi-Master。所有节点对等,依赖外部 ZooKeeper/ClickHouse Keeper 协调元数据和副本同步,部署和管理稍复杂。 | Master-Slave。有专门的 Master 节点管理集群元数据,易用性更好,但存在单点风险。 |
| 计算能力 | 极强。擅长复杂的 GROUP BY、JOIN、窗口函数等分析计算,主要用 C++ 编写,性能极致。 | 较弱。核心能力是搜索,数据分析能力相对有限。虽有 SQL 支持,但复杂分析场景不如 ClickHouse 高效。 |
| 生态与语言 | 原生 C++ 实现,无 JVM 依赖,对硬件利用更彻底,避免了 GC 停顿。 | 基于 Java(Lucene),成熟稳定,但在 GC 调优和内存管理上需投入更多精力。 |
# 2、为什么 ClickHouse 更快?(针对分析场景)
# 2.1 、列式存储
ES 行式 + 倒排 +_source 三套存储,查一条数据要加载整行;
CK 同一列连续存放,SQL 只用到哪几列就读哪几列,无关列完全不碰磁盘。
日志统计例子:
select count(*) where date='2026-07-01' and level='error'
CK 只读取date、level两列;ES 要读取完整每条日志 + 倒排索引。
同时同列数据类型统一、相似度极高,压缩比可达 1:8~1:10,同等日志 CK 磁盘占用仅 ES 1/5。
传统行式

列式

# 2.2、 MergeTree 分区 + 主键稀疏索引
CK 数据落盘强制两件事:
PARTITION BY 分区
(日志一般按天分区)
查询指定日期,直接丢弃整月 / 整年无关分区,完全不读取;直接跳过海量无关数据
ORDER BY 排序键 + 稀疏主键索引
每个数据块(granule,默认 8192 行)只存区间最大最小值,稀疏索引只记录块区间、不存每行;
查询
where level='error',会对比每个块level的 min/max,块内无 error 直接跳过整个文件
这个分区裁剪 + 块裁剪,实现了和倒排一样的效果:不用扫描全部数据,快速过滤掉绝大多数无关行。
ES 没有全局有序分片,只能靠倒排逐条匹配文档 ID,海量聚合场景效率差距巨大。
# 2.3、 跳数索引(Skip Index)
补充等值 / 模糊过滤,轻量化替代倒排。
CK 支持给字段建轻量级二级索引:MinMax、BloomFilter、Set 索引。
比如给message建布隆跳数索引:
查询message like '%error%',先用布隆过滤器判断当前数据块是否包含 error,无匹配直接跳过整块;
优势:跳数索引体积极小、合并成本低,不像 ES 倒排每条 term 都维护庞大 Posting List,不会磁盘爆炸。
举个例子:
块 A(存储一批正常 info 日志)
message 列日志内容:
user login success, cost 20ms
query db finish, code 200
heartbeat ok
块内单词:login、success、cost、query、finish、heartbeat
写入布隆:把这些词哈希后的 bit 全部标记为 1,error 从未出现,对应 bit 全是 0。
SQL:select * from log where message like '%error%',中块 A 绝对没有 error,整块直接跳过,不读磁盘。
如果 块 B 可能存在 error,必须加载这个块到内存逐行扫描验证,扫描块内所有 messag。
注意,如果你是使用 like '%err%' ,模糊匹配 %err% 匹配不到布隆里的 error,布隆无法帮你裁剪块,会失效,甚至会丢失数据。这要看是哪一种索引了
| 索引类型 | 工作原理 | 对 LIKE '%err%' 的效果 | 对 LIKE '%error%' 的效果 |
|---|---|---|---|
tokenbf_v1 | 按单词 (Token) 索引 | 无效 (无法匹配单词片段) | 有效 (匹配完整单词 error) |
ngrambf_v1 | 按固定长度 (N) 分割字符 | 可能有效 (取决于 N 的设置,如 ngrambf_v1(3) 能匹配 err) | 可能有效 |
text (倒排索引) | 全文搜索引擎式分词 | 有效 (功能最强,最推荐) | 有效 |
# 2.4、向量化执行
ClickHouse 在执行查询时,会将数据按批次(Block) 处理,每个批次包含多行数据。它能够利用 CPU 的 SIMD(单指令多数据流) 指令集,在一条 CPU 指令周期内同时对多个数据值执行相同操作(例如,同时对 16 个整数求和)。这使得 CPU 缓存命中率极高,数据处理吞吐量可以达到每秒数亿行。
ES 逐文档、逐行处理数据;
CK 把 8192 行打包成一个 Block 向量块,利用 CPU SIMD 单指令同时运算几十条数据。
就算极少数场景需要扫描某一列全部数据,CK 扫描速度也远高于 ES 遍历_source 脚本匹配,磁盘读出来的数据能瞬间完成过滤、求和、计数。
CK 不靠重型倒排,是用列式存储 + 分区块裁剪 + 稀疏索引 + 跳数索引 + 向量化计算组合方案完成海量数据过滤与统计;它天生为 OLAP 聚合设计,牺牲复杂全文检索能力换取极致压缩与统计性能;ES 靠倒排牺牲存储换取灵活关键词检索,两者优化目标完全不同。
# 3、CK 压缩率远高于 ES、极度节省磁盘
# 1. 存储结构天然差距(核心原因)
ES:同时维护三套独立存储
①倒排索引(text 字段分词生成海量 term,占用大量空间);单独维护一张大表:term → 所有 doc
②docValues 列式存储(用于排序聚合);
③_source 完整原始 JSON。三份数据叠加,存储直接膨胀 2~5 倍。
CK:仅存一份列式原始数据,无额外倒排 /docvalues 冗余结构;仅按需建轻量跳数索引,占用空间可忽略。
# 2. 列式数据压缩效率碾压行存
同一列数据类型统一、数值 / 字符串相似度极高,CK 内置 LZ4、ZSTD 深度压缩,同一份日志压缩体积仅 ES 的 1/3~1/8;
ES 行存储每行字段杂乱,压缩效果差,且多套索引会抵消压缩收益。
# 3. 数据分层裁剪减少存量数据
CK 依靠分区 + 稀疏索引,不会为检索存储冗余词条;ES 日志 message 设 text 分词会产生大量随机唯一 term(traceId、堆栈行号),倒排表持续膨胀。
# 4. 冷热分层差异化存储策略
热分离并不直接减小数据体积,而是通过将数据迁移至低成本存储来优化成本,而ClickHouse因其列式存储和高压缩比,在迁移前数据体积就已经很小,使得这一策略效果更显著;
相比之下,ES的倒排索引结构使得数据压缩困难,即使迁移,体积依然庞大,成本优势不明显。
# 5. 分片合并优化减少碎片冗余
CK 后台 Merge 会合并小分片、统一重压缩,清理无效数据;ES 大量小 segment 碎片会放大磁盘占用,删除文档仅标记不物理清除,冗余空间更多。
核心差异总结:(仅针对删除,不是针对自动过期)
- 无效数据处理逻辑天差地别
CK Merge:合并时直接过滤、物理丢弃删除行,彻底释放删除数据占用的磁盘;
ES Merge:仅整合删除标记,删除文档原始数据永久留在 segment,空间无法回收。
- 压缩机制不同
CK:合并后整块数据统一重压缩,同列数据集中,压缩效率极高;
ES:每个 segment 独立压缩,多套索引(倒排 + docvalues+_source)无法合并压缩,碎片越多膨胀越严重。
- 碎片冗余开销
CK 合并后只保留单个大分片,文件极少;
ES 小段过多时,每段都维护完整索引结构,文件数越多,磁盘冗余越大。
# 4、为什么clickhouse写入这么快
具体来说就是四点:
写入模型:批量块写入,拒绝单行刷盘(最关键)。
CK 客户端攒数据,攒满 8192 行(一个 Granule 粒度块) 才一次性写入磁盘,不会来一条写一条。(数据写入后立即可见(即使还未落盘此时在内存中))
ES 默认每条文档都会参与 refresh 刷segment段,1s 生成小段,大量随机 IO,频繁刷磁盘、构建倒排、维护副本同步。
每次写入只存新文件:每次数据写入,ClickHouse不会去碰旧数据,而是直接生成一个独立的小文件(Data Part)存到磁盘上。
而且MergeTree 写入无锁、无随机修改这种“只追加、不修改”的方式,避免了随机I/O,将写入操作简化为顺序写入,速度极快。
压缩后再存,省空间省I/O:数据按列存储,写入时自动用LZ4等算法压缩,压缩比极高。数据变小了,写入磁盘的数据量就少了,自然就快。
后台慢慢合并,不耽误写入:后台有个“合并”线程,会把这些小文件慢慢合并成大文件。即使数据过期、去重等操作,也在这个后台完成。ClickHouse 会在后台持续、自动地将多个小片段合并成更大的片段。这个合并过程是异步的,完全不影响正在进行的写入操作。
ES 后台 merge 会抢占磁盘 IO、CPU,高并发写入时经常出现写入阻塞、写入延迟飙升。
ES 只要 text 字段,写入时同步分词、构建 term 词典、PostingList 倒排,大量 CPU 计算;