ClickHouse|青训营笔记

108 阅读7分钟

ClickHouse|青训营笔记

这是我参与【第五届青训营】伴学笔记创作活动的第16天。

一、重点内容

  • 数据库分类、查询方式
  • 行存、列存数据库
  • Clickhouse的基础、底层实现
  • Clickhouse的应用

二、详细知识点

1. 数据库基本概念

  • 数据库概念:结构化信息/数据的有序集合,以电子形式存储在系统中
    • 结构化信息:数据解析整理成有序集合
    • 可以通过查询语言获取想要的信息

1.1 数据库类型

  • 数据库的类型

    • 关系型数据库:把数据以表方式储存,在各个表之间建立关系,通过表之间的关系操作不同表之间的数据
    • 非关系数据库:NoSQL或非关系数据库支持存储和操作半结构化及半结构化数据
      • 相较于关系型数据库无固定表结构
      • 无表表之间的关系
      • 数据间互相独立
  • 部署方式

    • 单机数据库:在一台计算机上完成数据查询存储的数据库
    • 分布式数据库:位于不同站点的两个以上文件组成,数据库可以存储在多台计算机上,位于同一个物理位置或分散在不同的网络上
  • 应用类型

    • OTAP数据库:高速分析数据库,为多用户大量事务设计
    • OLAP:同时分析多个数据维度,更好理解数据间的复杂关系

1.2 OLAP数据库

  • 大量数据读写,PB级存储
  • 多维分析,复杂聚合函数
  • 窗口函数,自定义UDF
  • 离线、实时分析

1.3 SQL

SELECT FROM WHERE GROUPBY HAVING ORDERBY LIMIT

  • 定义数据类型
  • 查询数据库数据
  • 优点
    • 标准化,ISO和ANSI长期建立SQL数据库标准
    • 高度非过程化,用SQL进行数据操作,用户无需理解操作方式只需提出做什么即可
    • 以同一语法结构提供两种使用方式
      • 可以直接进行查询
      • 可以嵌入其他语言中
    • 容易使用,容易学习与传播

1.4 数据库架构

  • client:解析SQL传递query
  • parser/optimizer/analyzer/executor
  • 进入存储引擎
    • index manager
    • transaction manager
    • file manager
    • cache manager

1.5 SQL执行

  • Parser:词法分析、语法分析、生成AST树
  • Analyzer:变量绑定,类型推导、语意检查、安全权限检查、完整性检查
  • Optimizer:为查询生成性能最优的执行计划,进行代价评估
  • Executor:将执行计划翻译成可执行的物理计划并驱动执行

1.6 存储引擎

  • 如何存储
    • 并发处理
    • 构建索引
    • 行列存
  • 读写数据需求不同
    • 读多写少
    • 读少写多
    • 点查场景
    • 分析性场景

2. 列存储

2.1 列存储的优点

  • 数据压缩可以使读的数据量更少,在IO密集型计算中有更大的性能优势
  • 相同类型压缩效率更高
  • 排序后压缩效率更高
  • 可以针对不同类型使用不同算法
    • LZ4:重复项越多越长压缩率更高
    • Run-length encoding:计算有多少个字符
    • delta encoding:数据存储为之前数据的差异
      • 直接在压缩数据计算,无需解压
  • 数据选择
    • 可以选择特定列计算而不需读所有列
    • 对聚合计算友好
  • 延迟物化:尽可能推迟物化操作发生
    • 缓存友好
    • CPU/内存带宽友好
    • 可以利用到执行计划和算子优化
    • 保留直接在压缩列做计算的机会
  • 向量化
    • SIMD:现代多核CPU有能力一条指令执行多条数据
    • 数据格式要求:处理多个数据,数据需要连续,需要明确数据类型
    • 列存数据库可以使用向量化技术
      • 按列读取
      • 每种列类型定义数据读写逻辑
      • 函数按列类型处理

2.2 行列存的比较

Screen Shot 2023-02-16 at 2.06.34 PM.png

3. ClickHouse存储设计

3.1 表定义和结构

  • 分布式表:不存储数据,用于将查询路由到集群的各个节点
    • cluster:逻辑集群,由多个节点组成
    • shard_key:指导数据写入分布式表时到分布方式
  • 本地表:实际存储数据的表
  • 结构
    • 集群选择 on CLUSTER
    • 引擎选择 engine=MergeTree()
    • 数据排列方式 ORDER BY
    • 数据如何在单节点分布 PARTITION BY

3.2 存储架构

  • 存储文件

    • part和column
      • column是一个文件
      • 所有column文件都在自己part文件夹下
    • column和index
      • 一个part有一个主key索引
      • 每个column都有列索引
  • 索引设计

    • hash index
      • 将输入key通过hash function映射到一组bucket上
      • 每个bucket包含一条指向一条记录的地址
      • 只适用于等值比较
    • B树
      • 数据写入有序,支持增删改查
      • 每节点有多个子节点
      • 每节点按照升序排列key
      • 每个key有指向左右子节点的引用
    • B+树
      • 所有数据都存储在叶子节点
      • 叶子节点维护到相邻叶子节点的引用
      • 通过key做二分查找,也可以通过叶子节点顺序访问
  • 问题

    • 对于大数据量B树深度太高
    • 索引数据量太大,多列如何平衡查询存储
    • OLAP场景写入量非常大如何优化写入
  • LSM tree为大吞吐写入而生

    • 着重优化顺序写入
    • 主要数据结构
      • SSTables
        • key按顺序存储到文件中,称为segment
        • 包含多个segment
        • 每个segment写入磁盘后不可更改
        • 新加入的数据智能生成新的segment
      • Memtable
        • 将内存中的数据保存在memtable中,大多数是binary search tree
        • 当memtable存储的数据到达一定阈值时会按顺序写入磁盘
    • 数据查询
      • 需要从最新的segment开始遍历每个key
      • 也可以为每个segment建立索引
    • 合并(compaction)
      • 将多个segments合并成一个
      • 一般由后台线程完成
      • 不同segmens写入新的segment时需要排序
      • 形成新segment后旧segment会被删除
  • 数据被划分为granules

    • granules是最小的读取单元
    • 不同之间可以平行读取
    • 每个granule对应primary.idx里一行
    • 每列会有一个mark文件保存每个granules地址
    • 缺陷:因数据按key排列,只有第一个key的过滤效果好,后面的key过滤效果依据第一个key的基数大小
  • 查询优化

    • secondary index:URL构建二级索引
    • 构建多个主key索引
      • 在建一个表
      • 建一个物化视图
        • 数据自动同步到隐式表
        • 查询需要用户判断查什么表
      • 使用projection
        • 类似物化视图,但不将数据写入新表
        • 查询自动路由到最优表
  • 数据合并

    • part内数据有序
    • 不同part内数据无序
    • 数据合并将多个part合并一起
  • 数据可见性

    • 数据合并过程中未被合并的数据对查询可见
    • 数据合并完成后新part可见,被合并的part被标记删除
  • 数据查询

    • 寻找对应列marks
    • 切分marks并发调度reader
    • reader通过mark offset得到需要读到文件偏移量
    • reader通过mark granule_offset得到解压后偏移量
    • 构建列式filter做数据过滤

4. 典型应用场景

4.1 大宽表存储查询

  • 可以建非常多的列
  • 增加删除清空列数据非常困难
  • 查询时候引擎可以快速选择需要的列
  • 可以将涉及到的过滤条件下推到存储引擎
  • 动态表结构
    • map中每个key都是一列
    • map中每列都能单独查询
    • 使用方式同普通列,可以做任何计算

4.2 离线数据分析

  • 数据导入
    • 数据通过spark生成clickhouse格式文件
    • 导入hdfs通过hive2ch导入
    • 数据直接导入到各个物理节点
    • 数据按列倒入
      • 保证查询可以及时访问已有数据
      • 可以按需加载需要的列

4.3 在线数据分析

  • 使用memorytable减少parts数量
    • 数据先缓存在内存中
    • 到达阈值后写入磁盘

4.4 复杂类型查询

  • bitmap索引创建(某值存在哪些行)
    • 读取时无需真正读取元文档
  • bitmap64类型
    • 压缩数据,group by bit
  • lowcardinality
    • 对低基数列使用字典编码
    • 减少数据存储读写IO使用
    • 可以做运行时压缩数据过滤

三、课程总结

今天的课程主要介绍了数据库和Clickhouse的相关知识。列存数据库是在日常学习中应用较少的一类,可能需要结合实际进行进一步的学习。