这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天
ClickHouse查询引擎
列存储的优点:
- 数据压缩(IO密集型计算) 相同类型压缩效率更高、排序后压缩效率更高、可以针对不同类型选择不同的压缩算法
- 数据选择上,可以选择特定列做计算而不是读所有列 对聚合计算友好
- 更方便延迟物化(将列数据转换为可以被计算或输出的行数据或内存数据) 对缓存友好、对CPU/内存带宽友好、可以利用到执行计划和算子的优化,如filter、保留直接在压缩列上计算的机会
- 更容易向量化(利用CPU的SIMD) 数据需要在内存中连续、数据类型必须明确;执行模型中,数据需按批读取、函数的调用需要明确数据类型
列存数据库适合设计出这样的执行模型,从而使用向量化计数:
- 按列读取
- 每种列类型定义数据读写逻辑
- 函数按列类型处理
分布式表:不存储数据,用于将查询路由到集群的各个节点
本地表:实际存储数据
索引设计
HashIndex:将输入的key通过一个hash function映射到一组bucket上;每个bucket都包含一个指向一条记录的地址 不适合大范围聚合查询
B-Tree:数据写入是有序的,支持增删改查;每个节点有多个孩子节点;每个节点按照升序排序key值;左孩子key都比当前小,右孩子key都比当前大
B+-Tree:所有数据都存在叶节点;叶节点维护到相邻叶节点的引用(双向链表),便于范围查找;可以通过key二分查找,也可以通过叶子节点顺序访问
对于大数据量,B(B+)-Tree深度太高
索引数据量太大,多个列如何平衡查询与存储? —— LSM-Tree
Log-structured merge-tree 针对大吞吐写入场景
- 着重优化顺序写入
- 主要数据结构:SSTables、Memtable
SSTables在磁盘以 segment 为粒度顺序存储key,每个segment写入磁盘后不可更高,只能写新segment 数据查询从最新的segment遍历key,也可以为每个segment建立索引
Memtable保存内存中的数据(一般Binary Search Tree实现,方便排序),缓存数据达到一定阈值时顺序写入磁盘
为了减少访问代价 & 索引存储代价,compaction将segments合并,一般由一个后台线程完成