四个交互演示:① Part 目录结构 · ② 稀疏索引跳 Granule 动画 · ③ 后台 Merge 合并动画 · ④ Skip Index 类型对比
以 events_mt 表为例,每个 Part 目录下都有三类文件:元数据 / 主键索引 / 列数据(每列独立 .bin + .mrk2)。
.bin,不碰别的列。{分区号}_{minBlock}_{maxBlock}_{level}。
比如 202401_5_9_1 表示"2024 年 1 月分区、已经合并过一轮(level=1)、块号区间 5~9"。
下面模拟一张有 120 个 Granule(每个 8192 行 ≈ 百万行) 的 Part,按主键 user_id 排序。
输入一个 user_id,点「查询」,看稀疏索引怎么二分 + 只命中少数几个 Granule。
primary.idx 只有 ~12000 条,可以常驻内存;
真正去磁盘读数据的 Granule 数通常只有 1~10 个。
点「插入一批」模拟一次 INSERT,生成一个 level=0 的新 Part;点「触发 Merge」让 MergeSelector 把相近大小的 Part 合并到更高 level。
parts_to_throw_insert(默认 300)时,新的 INSERT 会被拒绝 —— 这就是著名的 Too many parts 错误。所以千万不要高频小批量写入!
选择数据分布和查询类型,看哪种索引能跳得最干净。
minmax、低基数选 set(N)、高基数等值选 bloom_filter、字符串关键词选 tokenbf_v1、短串/中文选 ngrambf_v1。