ClickHouse查询引擎 | 青训营笔记

44 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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合并,一般由一个后台线程完成