土法炼钢 · 系统与基础设施

【列存引擎内核】索引与跳数索引

文章导航

分类入口
databasestorage
标签入口
#clickhouse#primary-key#data-skipping-index#minmax#bloom-filter#sparse-index#24-lts

目录

ClickHouse 的 PRIMARY KEY 不是唯一约束——它是 稀疏排序索引,每 granule 一条,配合物理排序做 granule 剪枝。二级 Data Skipping Index 进一步跳过 granule,与 PG B-Tree 指针索引本质不同。


一、稀疏主键

primary.idx:granule \(i\) 存该行 ORDER BY 前缀键值。

查询 WHERE date >= '2024-01-01' AND date <= '2024-01-31' → 二分 primary.idx → Mark Range。

不能保证 WHERE id = 1 只读一行——可能读整个 granule(最多 index_granularity 行)。

flowchart TB
  PK[primary.idx 每 granule 1 键]
  PK --> R[Mark Range]
  R --> READ[读 granule 内所有行再 filter]

二、ORDER BY 与 PRIMARY KEY

PRIMARY KEY 必须是 ORDER BY 前缀;可 ORDER BY (a,b,c) PRIMARY KEY (a,b) 减少索引体积。

排序键选择决定 merge 归并顺序与剪枝效果——DDL 核心设计


三、Data Skipping Index

ALTER TABLE t ADD INDEX idx_url url TYPE bloom_filter GRANULARITY 4;
类型 机制
minmax granule 内 min/max
set 值集合(有大小限制)
bloom_filter 等值探测
tokenbf_v1 分词 bloom

GRANULARITY n:每 \(n\) 个 granule 一条索引项。文件 skp_idx_* .idx + .mrk2

flowchart TB
  Q[WHERE url = ?] --> PK[primary.idx 剪枝]
  PK --> SK[bloom_filter 跳数索引]
  SK --> G1[Granule 跳过]
  SK --> G2[Granule 保留 → 读列]
  G2 --> MRK[Mark → .bin]

四、与 PG B-Tree 对照

PG B-Tree CH 稀疏 PK + Skip
粒度 行/页 granule
唯一 可 UNIQUE 不唯一
二级 任意列 B-Tree 跳数索引,非精确
维护 每行更新 insert/merge 批量写

五、设计建议


六、EXPLAIN indexes=1

第 5 篇 联用,查看 Skip 索引排除 granule 数。本环境无实例,不贴输出。


七、学术谱系:稀疏主键 · Zone Map · Skip Index

阶段 概念 / 文献坐标 本篇落点
行存 B-Tree 定位行(PG 14-btree 对照:CH PK 定位行
列存经典 Zone map / min-max 段摘要 minmax 跳数索引;PK 稀疏边界
C-Store 排序投影利于范围 ORDER BY / PRIMARY KEY 前缀
CH set / bloom skip index 辅助剪枝,非第二套 B-Tree

争论:多建 skip index 换剪枝 vs 索引维护与空间。错误索引「几乎无剪枝还占空间」(第五节)——与 Abadi「系统栈要完整」一致:索引必须服务真实谓词。

7.1 工程间隙

论文 / 教科书 ClickHouse
理想均匀分区 时间歪斜导致 PK 前缀失效
Projection 作主加速手段 CH 主路径仍是排序键 + skip;PROJECTION 可选(第 01 篇开放问题)

7.2 开放问题

  1. Projection 与 skip index 职责如何划分? 可检验:同查询只加 projection vs 只加 bloom 的 EXPLAIN indexes 与 parts 体积。
  2. 自适应跳数索引(按查询历史推荐)——研究与产品都在演进,无统一标准。

八、小结

索引 = 减少 granule,不是 定位行。理解这一点可避免把 ClickHouse 当 OLTP 主库。


上一篇Merge 与 Mutation

下一篇ReplicatedMergeTree


参考资料

核心论文

  1. Stonebraker et al., C-Store, VLDB 2005(排序投影;A 级)。
  2. Abadi et al., FnT DB 2013 综述中的 zone-map / 段摘要坐标(A 级)。

规范 / 源码 / 文档

  1. ClickHouse Documentation, Primary KeysData Skipping Indexes(A 级)。
  2. PostgreSQL 系列, B-Tree(对照)。

稀疏主键 vs B-Tree

PG B-Tree 叶项指向 heap tuple(14-btree);CH primary.idx 每 granule 一条,不指向行,只用于 granule 范围剪枝。

跳数索引类型

类型 存储 适用
minmax 每 granule min/max 范围谓词
set granule 内值集合(有上限) IN 列表
bloom_filter Bloom 高基数等值
tokenbf_v1 / ngrambf_v1 文本 token LIKE 辅助

定义在 INDEX idx_name expr TYPE ... GRANULARITY gGRANULARITY 表示每多少个 granule 写一条索引项。

Mark Range 算法(概念)

对每个 Part:

  1. primary.idx 二分/扫描,找与 PK 谓词相交的 granule 下标区间 \([g_{lo}, g_{hi}]\)
  2. 跳数索引进一步缩小区间(第 7 篇)。
  3. 对每列 Mark 文件取 \([g_{lo}, g_{hi}]\) 对应压缩块并解压。
  4. PREWHERE 列优先读,结果位图过滤后再读其余列(若优化器下推)。

PREWHERE 语义

PREWHERE 不是语法糖:优化器将选择性高的条件移到存储层,减少列 IO。官方建议高选择性条件放 PREWHERE;WHERE 其余 predicate 在内存 Block 上执行。

并行

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。

2026-06-18 · database / storage

【列存引擎内核】列存基础与 ClickHouse 架构

行存 vs 列存的带宽、压缩与向量化三角;ClickHouse Server 进程模型、线程池与 MergeTree 引擎家族地图;src/Storages 与 src/Processors 源码入口。对照 PG 行存与 LSM 写优化路径,版本锚定 ClickHouse 24.x LTS。

2026-06-18 · database / storage

【列存引擎内核】MergeTree Part 文件格式

ClickHouse MergeTree Part 目录结构:columns.txt、checksums.txt、.bin、.mrk2、primary.idx 语义,Granule 与 Mark 的定位作用,Wide/Compact 布局与 MergeTreeDataPart 源码入口。版本锚定 24.x LTS。

2026-06-18 · database / storage

【列存引擎内核】压缩与编码

ClickHouse 列压缩:LZ4、ZSTD、Delta、DoubleDelta、Gorilla 时序编码与列类型关系;CODEC 链顺序、LowCardinality 与 PG TOAST 对照。压缩比须本机实测,本文不编造倍数。

2026-06-18 · database / storage

【列存引擎内核】向量化执行引擎

ClickHouse Block 列向量 batch、IProcessor Pipeline 与 filter/project/aggregate 向量实现;对照 PostgreSQL 火山模型 ExecProcNode。源码入口 src/Processors、src/Columns。24.x LTS。


By .