Post

Clickhouse学习笔记

Clickhouse学习笔记

概述

  • 端口8123:tcp转发
  • 端口9000:http转发
  • 端口9009:interserverHTTPPort
  • 列式存储:磁盘存储按列存储
  • 多核并行:分区间并行处理数据(查询,合并等)
  • 多种表引擎:常用MergeTree Family,Log Family,Integrations
  • 写入建议:一批大于1000行,或每秒不超过一个写入请求

数据类型

常见类型

  • 整型:Int8、Int16、Int32、Int64;UInt8、UInt16、UInt32、UInt64
  • 浮点型:Float32、Float64
  • 布尔值:无该类型,用UInt8代替
  • 字符串:String,FixedString(N)
  • 时间类型:Date,Datetime,Datetime64

数组

LowCardinality

对数据类型进行二次字典编码;修改底层数据存储

Map

  • 本质上是一种语法糖,底层是两个等长数组:keys Array(K) + values Array(V)
  • 不保证 key 唯一性
  • KV 都是强类型

AggregateFunction

  • 以二进制形式存储中间态数据,不同数据类型,底层辅助结构不同,如uniq 的 hash set
  • insert 时调用 state 类函数(如MinState、MaxState)生成中间状态,select 时调用 merge 类函数(如MinMerge、MaxMerge)读取最终结果
  • 占用存储空间大
  • 常用于求集合状态 ,如topK、 unique 场景

SimpleAggregateFunction

  • 和普通数据类型列一样。如SimpleAggregateFunction(sum, UInt64)底层就是UInt64列,没有中间态数据,没有额外辅助结构

    为什么不直接定义普通数据列?如 UInt64

    答:因为在 merge 阶段,SimpleAggregateFunction可以做聚合操作(如 sum,max,min),而普通类型不支持 merge 聚合。SimpleAggregateFunction一般搭配AggregatingMergeTree表引擎

  • 占用存储空间小
  • 常用于求单一结果,如min、max、sum 场景

枚举

对比LowCardinality,枚举更加适合静态字典的场景

目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
root@/data/clickhouse# tree -L 1
.
|-- data                    // 数据、表元数据
|-- format_schemas
|-- log                     // ck-server日志文件
`-- tmp

root@/data/clickhouse/data# tree -L 1
.
|-- data                    // 数据、索引文件
|-- dictionaries_lib
|-- flags
|-- metadata                // 表元数据
|-- metadata_dropped
|-- preprocessed_configs
|-- status
`-- store                   // data下数据文件是以软连接到store目录

// 表partition
root@/data/clickhouse/data/data/{database}/{table}# tree -L 1
.
|-- 20220917_20_20_0        // patition
|-- 20220917_21_21_0
|-- detached                // 记录损坏partition
`-- format_version.txt      // version

// partition目录
root@/data/clickhouse/data/data/{database}/{table}/{patition}# tree -L 1
.
|-- checksums.txt                   // 校验文件
|-- columns.txt                     // 列信息(字段名、类型)
|-- count.txt                       // 总数
|-- data.bin                        // 数据
|-- data.mrk3                       // 数据标记文件,索引文件会用到该标记
|-- default_compression_codec.txt   // 压缩
|-- minmax_timestamp.idx            // 分区minimal索引
|-- partition.dat                   // 分区信息
`-- primary.idx                     // 主键索引

partition命名规则

1
2
3
4
5
6
20220917_1_1_0
[分区名]-[最小分区块编号]-[最大分区块编号]-[合并数次]

分区名:跟partition by参数有关,有整数字符串、日期、哈希值
分区块编号:新生成的分区自增
合并数次:合并一次加1

表引擎

MergeTree

  • 支持索引和分区
  • partition by(optional):指定分区规则,一般是按时间
  • primary key(optional):主键,只提供一级索引,没有唯一约束
  • order by(required):分区内排序,主键必须是order by字段的前缀字段
  • settings(optional):一些额外控制参数,如index_granularity索引粒度,默认8192
  • TTL:支持列ttl,表级ttl
  • 参考:https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree

ReplacingMergeTree

SummingMergeTree

Distributed

img.png{:height=”10%” width=”50%”}

MergeTree与ReplicatedMergeTree区别

索引(MergeTree)

参考:https://sobriver.top/2021/07/07/%E7%BC%96%E7%A8%8B/clickhouse/clickhouse%E7%B4%A2%E5%BC%95%E5%8E%9F%E7%90%86%E4%BB%8B%E7%BB%8D/

主键索引

低层数据结构是有序数组,采用二分查找

  • 没有唯一约束
  • 稀疏索引;不是每行数据都建立索引;保存每个granule的order by建最小值
  • 由建表语句index_granularity指定索引粒度,默认8192

分区索引

  • 记录分区下分区字段对应原始数据的最小和最大值
  • 查询语句指定分区字段时,通过该索引快速定位到分区

跳数索引

作用于非主键列。没有固定的数据结构,默认4个granule生成一个元信息摘要,如: granule[1-4] -> minmax[1, 99],granule[1-4] -> bloom()

  • INDEX index_name expr TYPE type(…) GRANULARITY granularity_value,type:minmax, set, bloom_filter等
  • minmax:指定一个值范围
  • set(max_rows):保存表达式去重复后值,适用重复性高的字段
  • bloom_filter([false_positive]):布隆过滤器,false_positive为误报率
  • ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed):对String, FixedString 和 Map类型数据有效,可用于优化 EQUALS, LIKE 和 IN表达式。
  • tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed):适用全文搜索

排序key

  • 不是传统意义上的索引,决定数据在磁盘上的物理排序
  • 分区数据按order by字段排序,显著提升范围查询和排序操作的性能

参考

explain

是否走索引

副本同步原理

img.png{:height=”10%” width=”50%”}

  • 1、client向某个server1发送写入请求
  • 2、server1写入本地
  • 3、同步operation log到zookeeper
  • 4、其他server监听到operation log变化并拉取operation log
  • 5、解析operation log,并从server1拉取数据
  • 总结:
  • 1、谁处理client请求,谁负责。负责同步operation log数据到zookeeper
  • 2、zookeeper不参与实质的data数据传输,只负责log同步

分区操作

数据与压缩压缩

Clickhouse 的压缩比由编码算法压缩算法共同决定。

编码算法

  • Delta:存储每行与前一行的差值
  • DoubleDelta:两阶段Delta(数据Delta后,在Delta)。正确使用,压缩比比Delta更高
编码原理适合场景
Delta存储每行与前一行的差值递增数据,如:时间戳、ID
DoubleDelta二阶Delta,数据Delta后,再Delta固定间隔序列,如:时间序列
Gorilla如果两个浮点数 变化很小,那么 XOR 后只有少量 bit 不同。只存变化的 bitmetrics
T64删除高位为 0 的 bit小整数
LowCardinality字典编码枚举

压缩算法

压缩原理压缩率压缩速度解压速度适合场景
LZ4用“引用历史数据的位置”代替重复的数据。极快极快Clickhouse默认
ZSTDLZ77(类似LZ4)+ 熵编码(高频数据 → 短编码;低频数据 → 长编码)通用推荐
ZSTD(level)ZSTD变种很高冷数据

参考:

参数调优

在system.settings表中可查

  • background_pool_size:后台线程池大小,影响merge partition速度,默认16,建议为cpu个数2倍
  • max_memory_usage: 单次query占用最大值,默认10G
  • max_table_size_to_drop: 删除分区时,限制的可删除大小

速度,

总结

  • clickhouse采用列式存储,适合OLAP场景
  • 多种数据类型,不支持Bool,LowCardinality对数据类型进行二次编码
  • 常用MergeTree序列表引擎,关键字段:partition by,primary key,order by,settings
  • 索引:主键索引,分区索引,跳数索引
  • 常用分区操作

参考

This post is licensed under CC BY 4.0 by the author.