在 ClickHouse 中,合并后的 Part 仅保证逻辑有序(按主键) 是其高性能查询的核心机制,这一特性通过 多层索引系统、稀疏标记与数据分块 实现。理解其原理需要对比物理连续性,从逻辑组织、存储结构、查询流程三个维度展开:

1. 物理连续 vs 逻辑有序:核心差异

对比维度物理连续存储逻辑有序存储(ClickHouse 实现)
数据布局 数据按顺序存放在相邻磁盘块中 数据分块存储,块间物理位置可能不连续
索引依赖 依赖磁盘物理地址直接定位 依赖多层索引(主键索引、标记文件)定位
写入效率 需预先分配连续空间,写入时可能产生碎片 无需连续空间,支持追加写入,碎片少
查询效率 范围查询需按物理顺序扫描 范围查询通过索引快速定位数据块,无需顺序扫描
典型应用场景 文件系统日志、数据库 redo log LSM-Tree 数据库(如 ClickHouse、LevelDB)

2. ClickHouse 逻辑有序的底层实现细节

1. 多层索引系统:稀疏索引 + 标记文件

ClickHouse 通过 两级索引 实现逻辑有序数据的高效访问:
  • 主键索引(primary.idx
    存储 稀疏索引,每隔 8192 行记录一次主键值及其对应数据块的起始偏移量。例如:
    # primary.idx 文件内容示例(简化)
    主键值      数据文件偏移量
    ───────────────────
    100         0x000000
    200         0x001400  ← 表示主键值≥200的数据从偏移量0x001400开始
    300         0x002800
    作用:快速定位查询范围对应的大致数据块。
  • 标记文件(marks.mrk2
    记录每个数据块在文件中的 精确位置,与主键索引配合使用。例如:
    # marks.mrk2 文件内容示例(简化)
    数据块序号   数据文件偏移量   压缩块偏移量
    ──────────────────────────────
    0          0x000000         0x000000
    1          0x000500         0x000123  ← 第1个数据块的起始位置
    2          0x000A00         0x000246
    作用:在主键索引定位的大致范围内,进一步精确定位具体数据块。

2. 数据分块存储:granule 与 block

ClickHouse 将数据按 粒度(granule) 组织,每个粒度包含约 8192 行数据,对应主键索引中的一个索引项。每个粒度又被拆分为多个 数据块(block),每个块包含压缩后的数据。例如:
# 数据文件(data.bin)内部结构
┌─────────────────────────────────────┐
│ 块1 (granule 0, rows 0-8191)        │
├─────────────────────────────────────┤
│ 块2 (granule 0, rows 8192-16383)    │
├─────────────────────────────────────┤
│ 块3 (granule 1, rows 16384-24575)   │
└─────────────────────────────────────┘
特点:
  • 同一粒度内的数据按主键有序,但不同粒度的物理位置可能不连续。
  • 查询时,先通过主键索引定位到对应粒度,再通过标记文件读取具体数据块。

3. 查询流程:从逻辑到物理的映射

假设查询 WHERE id BETWEEN 201 AND 299,ClickHouse 的执行流程如下:
  1. 主键索引查找:
    在 primary.idx 中找到 200 → 0x001400 和 300 → 0x002800,确定数据范围在这两个偏移量之间。
  2. 标记文件定位:
    在 marks.mrk2 中查找偏移量 0x001400 和 0x002800 对应的具体数据块(如块 3-5)。
  3. 磁盘读取:
    根据标记文件的指引,从 data.bin 中读取块 3-5 的数据,解压后返回符合条件的记录。
关键点:
  • 查询无需扫描全量数据,仅读取索引命中的特定数据块。
  • 即使数据块在物理上不连续,通过索引仍能高效定位,逻辑有序性完全由索引保证。

3. 逻辑有序的优势与代价

3.1. 优势

  • 写入高效:无需预先分配连续空间,支持追加写入,适合高并发场景。
  • 查询高效:通过索引快速定位,避免全表扫描,范围查询性能接近物理连续存储。
  • 抗磁盘碎片:数据分块存储,文件系统碎片不影响查询效率。

3.2. 代价

  • 索引空间开销:主键索引和标记文件占用额外存储空间(通常为主数据的 1-5%)。
  • 随机读增加:查询时需多次随机读取索引文件和数据文件(但 SSD 可有效缓解)。
  • 合并复杂度提升:合并时需维护多层索引的一致性,增加 CPU 和内存消耗。

4. 对比案例:物理连续 vs 逻辑有序的查询表现

假设表 users 包含 1 亿行数据,按 user_id 排序,查询 WHERE user_id BETWEEN 1000000 AND 1000010

4.1. 物理连续存储

  • 优势:数据按 user_id 顺序存放在相邻磁盘块中,范围查询可通过一次顺序读完成。
  • 劣势:写入时需预留连续空间,碎片管理复杂;更新或删除操作可能导致空间浪费。

4.2. ClickHouse 逻辑有序存储

  • 优势:通过主键索引直接定位到目标数据块(假设位于偏移量 0x1000000 和 0x1000100),仅需读取这两个位置的数据块,无需扫描中间无关数据。
  • 劣势:需先读取主键索引(随机读),再读取数据块(可能也是随机读,取决于文件系统)。

5. 总结:为什么 ClickHouse 选择逻辑有序?

  1. 写入性能优先:
    逻辑有序支持无锁追加写入,适合实时数据摄入场景(如每秒百万级写入)。
  2. 查询性能可接受:
    现代 SSD 的随机读性能已大幅提升,多层索引机制能有效减少随机读次数,使逻辑有序的查询效率接近物理连续。
  3. 架构扩展性:
    逻辑有序架构天然支持分布式存储(如 ClickHouse 的分布式表引擎),不同分片的数据无需物理连续即可协同工作。
  4. 抗故障能力:
    数据分块存储,单个数据块损坏不影响整体查询,修复成本低(仅需重新复制损坏块)。

理解这些原理后,可更好地优化 ClickHouse 表结构(如合理设置 index_granularity)和硬件配置(如使用 NVMe SSD 提升随机读性能),充分发挥逻辑有序存储的优势。
 posted on 2025-07-28 10:50  xibuhaohao  阅读(16)  评论(0)    收藏  举报