HelloCoder HelloCoder
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
  • 《k8s学习心得》
随笔
关于作者
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
  • 《k8s学习心得》
随笔
关于作者
  • 《从0到1学习Java多线程》

  • 《从0到1搭建服务器》

  • 源码学习

  • 可观测和监控

    • 可观测是什么
    • 指标
    • 链路
    • 日志
    • Zabbix vs Prometheus
    • 基于Micrometer的Prometheus指标生成
    • OpenTelemetry
    • Opentelemetry Collector
    • Opentelemetry尾采样
    • 基于Opentelemetry的filelog插件收集日志
    • Python接入Opentelemetry
    • 基于javaagent探针自动埋点
    • 可观测系统在Flyme落地
    • javaagent的类加载器
    • prometheus指标脱坑
    • 中间件标准化落地
    • 为什么选择Clickhouse而不是ElasticSearch?
    • 使用vm-agent替代prometheus
    • javaagent实现
    • 跨线程传递Context
  • 玩转IDEA

  • AI学习

  • 03-RPC

  • 05-《Java日志框架》

  • k8s

  • 专栏
  • 可观测和监控
#Clickhouse #ElasticSearch #为选择 #而不是
HaC
2026-07-01
目录

为什么选择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 数据落盘强制两件事:

  1. PARTITION BY 分区

    (日志一般按天分区)

    查询指定日期,直接丢弃整月 / 整年无关分区,完全不读取;直接跳过海量无关数据

  2. 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写入这么快

具体来说就是四点:

  1. 写入模型:批量块写入,拒绝单行刷盘(最关键)。

    CK 客户端攒数据,攒满 8192 行(一个 Granule 粒度块) 才一次性写入磁盘,不会来一条写一条。(数据写入后立即可见(即使还未落盘此时在内存中))

    ES 默认每条文档都会参与 refresh 刷segment段,1s 生成小段,大量随机 IO,频繁刷磁盘、构建倒排、维护副本同步。

  2. 每次写入只存新文件:每次数据写入,ClickHouse不会去碰旧数据,而是直接生成一个独立的小文件(Data Part)存到磁盘上。

    而且MergeTree 写入无锁、无随机修改这种“只追加、不修改”的方式,避免了随机I/O,将写入操作简化为顺序写入,速度极快。

  3. 压缩后再存,省空间省I/O:数据按列存储,写入时自动用LZ4等算法压缩,压缩比极高。数据变小了,写入磁盘的数据量就少了,自然就快。

  4. 后台慢慢合并,不耽误写入:后台有个“合并”线程,会把这些小文件慢慢合并成大文件。即使数据过期、去重等操作,也在这个后台完成。ClickHouse 会在后台持续、自动地将多个小片段合并成更大的片段。这个合并过程是异步的,完全不影响正在进行的写入操作。

ES 后台 merge 会抢占磁盘 IO、CPU,高并发写入时经常出现写入阻塞、写入延迟飙升。

ES 只要 text 字段,写入时同步分词、构建 term 词典、PostingList 倒排,大量 CPU 计算;

#Clickhouse#ElasticSearch#为选择#而不是
上次更新: 2026-07-01 15:23:28
最近更新
01
脏读、幻读
07-01
02
elasticsearch面试题
07-01
03
G1、ZGC有了解过吗?
07-01
更多文章>
Theme by Vdoing | Copyright © 2020-2026 HaC
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式