AIGC在金融场景是如何落地的? 了解详情
写点什么

ClickHouse 核心引擎 MergeTree 解读

  • 2021-04-07
  • 本文字数:4431 字

    阅读完需:约 15 分钟

ClickHouse核心引擎MergeTree解读

ClickHouse 是俄罗斯最大的搜索引擎 Yandex 在 2016 年开源的数据库管理系统(DBMS),主要用于联机分析处理(OLAP)。其采用了面向列的存储方式,性能远超传统面向行的 DBMS,近几年受到广泛关注。


本文将介绍 ClickHouse MergeTree 系列表引擎 的相关知识,并通过示例分析 MergeTree 存储引擎的数据存储结构。

1 MergeTree 表引擎简介

MergeTree(合并树)系列表引擎是 ClickHouse 提供的最具特色的存储引擎。MergeTree 引擎支持数据按主键、数据分区、数据副本以及数据采样等特性。官方提供了包括 MergeTree、ReplacingMergeTree、SummingMergeTree、AggregatingMergeTree、CollapsingMergeTree、VersionedCollapsingMergeTree、GraphiteMergeTree 等 7 种不同类型的 MergeTree 引擎的实现,以及与其相对应的支持数据副本的 MergeTree 引擎(Replicated*)。



首先来介绍一下 MergeTree 核心引擎


ReplacingMergeTree: 在后台数据合并期间,对具有相同排序键的数据进行去重操作。


SummingMergeTree: 当合并数据时,会把具有相同主键的记录合并为一条记录。根据聚合字段设置,该字段的值为聚合后的汇总值,非聚合字段使用第一条记录的值,聚合字段类型必须为数值类型。


AggregatingMergeTree: 在同一数据分区下,可以将具有相同主键的数据进行聚合。


CollapsingMergeTree: 在同一数据分区下,对具有相同主键的数据进行折叠合并。


VersionedCollapsingMergeTree


基于 CollapsingMergeTree 引擎,增添了数据版本信息字段配置选项。在数据依据 ORDER BY 设置对数据进行排序的基础上,如果数据的版本信息列不在排序字段中,那么版本信息会被隐式的作为 ORDER BY 的最后一列从而影响数据排序。


GraphiteMergeTree: 用来存储时序数据库 Graphites 的数据。


MergeTree 是该系列引擎中最核心的引擎,其他引擎均以 MergeTree 为基础,并在数据合并过程中实现了不同的特性,从而构成了 MergeTree 表引擎家族。下面我们通过 MergeTree 来具体了解 MergeTree 表系列引擎。

2 MergeTree 引擎

2.1 表创建

创建 MergeTree 的 DDL 如下所示:


CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster] (      name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],       name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],       ... ) ENGINE = MergeTree()  ORDER BY expr   [PARTITION BY expr]   [PRIMARY KEY expr]   [SAMPLE BY expr]   [TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]   [SETTINGS name=value, ...
复制代码


这里说明一下 MergeTree 引擎的主要参数:


  • 必填选项

  • ENGINE :引擎名字,MergeTree 引擎无参数。

  • ORDER BY :排序键,可以由一列或多列组成,决定了数据以何种方式进行排序,例如 ORDER BY(CounterID, EventDate)。如果没有显示指定 PRIMARY KEY,那么将使用 ORDER BY 作为 PRIMARY KEY。通常只指定 ORDER BY 即可。

  • 选填选项

  • PARTITION BY :分区键,指明表中的数据以何种规则进行分区。分区是在一个表中通过指定的规则划分而成的逻辑数据集。分区可以按任意标准进行,如按月、按日或按事件类型。为了减少需要操作的数据,每个分区都是分开存储的。

  • PRIMARY KEY :主键,设置后会按照主键生成一级索引(primary.idx),数据会依据索引的设置进行排序,从而加速查询性能。默认情况下,PRIMARY KEY 与 ORDER BY 设置相同,所以通常情况下直接使用 ORDER BY 设置来替代主键设置。

  • SAMPLE BY :数据采样设置,如果显示配置了该选项,那么主键配置中也应该包括此配置。例如 ORDER BY CounterID / EventDate / intHash32(UserID)、SAMPLE BY intHash32(UserID)。

  • TTL :数据存活时间,可以为某一字段列或者一整张表设置 TTL,设置中必须包含 Date 或 DateTime 字段类型。如果设置在列上,那么会删除字段中过期的数据。如果设置的是表级的 TTL,那么会删除表中过期的数据。如果设置了两种类型,那么按先到期的为准。例如,TTL createtime + INTERVAL 1 DAY,即一天后过期。使用场景包括定期删除数据,或者定期将数据进行归档。

  • index_granularity :索引间隔粒度。MergeTree 索引为稀疏索引,每 index_granularity 个数据产生一条索引。index_granularity 默认设置为 8092。

  • enable_mixed_granularity_parts :是否启动 index_granularity_bytes 来控制索引粒度大小。

  • index_granularity_bytes :索引粒度,以字节为单位,默认 10Mb。

  • merge_max_block_size :数据块合并最大记录个数,默认 8192。

  • merge_with_ttl_timeout :合并频率最小时间间隔,默认 1 天。

2.2 数据存储结构

首先创建一个 test 表,DDL 如下:


CREATE TABLE test.test (     id        UInt64,     type      UInt8,     create_time DateTime ) ENGINE = MergeTree()   PARTITION BY toYYYYMMDD(create_time)   ORDER BY (id)   SETTINGS index_granularity = 4;
复制代码


test 表包括 id、type、create 等三个字段,其中以 create_time 日期字段作为分区键,并将日期格式转化为 YYYYMMDD。按照 id 字段进行排序。由于没有显式设置主键,所以引擎默认使用 ORDER BY 设置的 id 列作为索引字段,并生成索引文件。index_granularity 设置为 4,意味着每 4 条数据产生一条索引数据。


插入一条测试数据:


insert into test.test(id, type, create_time) VALUES (1, 1, toDateTime('2021-03-01 00:00:00'));
复制代码


使用如下命令查看 test 表分区相关信息:


 SELECT         database,         table,         partition,         partition_id,         name,         active,         path  FROM system.parts  WHERE table = 'test' 
复制代码


返回结果如下图所示:



从上图中可以看到 test 表中返回了一条 partitionid 为 20210301 的数据分区的记录,从 name 字段中我们可以得知,此分区的目录名为 20210301_8_8_0。20210301_8_8_0 这个目录名字到底有什么含义呢?下面来介绍一下分区规则以及分区目录的命名规则。

2.2.1 数据分区 ID 生成规则

数据分区规则由分区 ID 决定,分区 ID 由 PARTITION BY 分区键决定。根据分区键字段类型,ID 生成规则可分为:


  • 未定义分区键

  • 没有定义 PARTITION BY,默认生成一个目录名为 all 的数据分区,所有数据均存放在 all 目录下。

  • 整型分区键

  • 分区键为整型,那么直接用该整型值的字符串形式做为分区 ID。

  • 日期类分区键

  • 分区键为日期类型,或者可以转化成日期类型。

  • 其他类型分区键

  • String、Float 类型等,通过 128 位的 Hash 算法取其 Hash 值作为分区 ID。


上面我们插入一条日期为 2021-03-01 00:00:00 的数据,对该字段格式化后生成的数据分区 id 就是 20210301。

2.2.2 数据分区目录命名规则

目录命名规则如下:


PartitionId_MinBlockNum_MaxBlockNum_Level
复制代码


  • PartitionID

  • 分区 id,例如 20210301。

  • MinBlockNum

  • 最小分区块编号,自增类型,从 1 开始向上递增。每产生一个新的目录分区就向上递增一个数字。

  • MaxBlockNum

  • 最大分区块编号,新创建的分区 MinBlockNum 等于 MaxBlockNum 的编号。

  • Level

  • 合并的层级,被合并的次数。合并次数越多,层级值越大。



从上图可知,此分区的分区 id 为 20210301,当前分区的 MinBlockNum 和 MinBlockNum 均为 8,而 level 为 0,表示此分区没有合并过。

2.3 数据分区文件组织结构

在了解了分区目录名字的生成规则后,下面来看看数据分区目录下的文件组织结构。以 2021030188_0 分区为例:



从图中可以看到,目录中的文件主要包括 bin 文件、mrk 文件、primary.idx 文件以及其他相关文件。


  • bin 文件

  • 数据文件,存储的是某一列的数据。数据表中的每一列都对应一个与其字段名相同的 bin 文件,例如 id.bin 存储的是表 test 中 id 列的数据。

  • mrk 文件

  • 标记文件,每一列都对应一个与其字段名相同的标记文件,标记文件在 idx 索引文件和 bin 数据文件之间起到了桥梁作用。以 mrk2 结尾的文件,表示该表启用了自适应索引间隔。

  • primary.idx 文件

  • 主键索引文件,用于加快查询效率。

  • count.txt

  • 数据分区中数据总记录数。上述 20210301_8_8_0 的数据分区中,该文件中的记录总数为 1。

  • columns.txt

  • 表中所有列数的信息,包括字段名和字段类型。

  • partion.dat

  • 用于保存分区表达式的值。上述 20210301_8_8_0 的数据分区中该文件中的值为 20210301。

  • minmax_create_time.idx

  • 分区键的最大最小值。

  • checksums.txt

  • 校验文件,用于校验各个文件的正确性。存放各个文件的 size 以及 hash 值。

2.3.1 数据文件

MergeTree 中,每列都对应一个 bin 文件单独存放该列数据。例如,id.bin 存放的是 id 列的数据。所有数据都经过数据压缩、排序,最后以数据块的形式写入 bin 文件中。bin 中数据以压缩数据块为单位写入文件中。每个数据块由头信息和压缩数据组成。头部信息包括校验和、数据压缩算法、数据压缩前大小和压缩后大小组成。压缩数据由 granule 组成,granule 大小与 index_granularity 相关。

2.3.2 索引文件

MergeTree 索引为稀疏索引,它并不索引单条数据,而是索引一定范围的数据。也就是从已排序的全量数据中,间隔性的选取一些数据记录主键字段的值来生成 primary.idx 索引文件,从而加快表查询效率。间隔设置参数为 index_granularity。



我们向表 test 中插入 9 条数据,


insert into test.test(id, type, create_time) VALUES (1, 1, toDateTime('2021-03-01 00:00:00')); insert into test.test(id, type, create_time) VALUES (1, 2, toDateTime('2021-03-01 00:00:00')); insert into test.test(id, type, create_time) VALUES (1, 3, toDateTime('2021-03-01 00:00:00')); insert into test.test(id, type, create_time) VALUES (2, 1, toDateTime('2021-03-01 00:00:00')); insert into test.test(id, type, create_time) VALUES (2, 1, toDateTime('2021-03-01 00:00:00')); insert into test.test(id, type, create_time) VALUES (3, 1, toDateTime('2021-03-01 00:00:00')); insert into test.test(id, type, create_time) VALUES (3, 1, toDateTime('2021-03-01 00:00:00')); insert into test.test(id, type, create_time) VALUES (4, 1, toDateTime('2021-03-01 00:00:00')); insert into test.test(id, type, create_time) VALUES (5, 1, toDateTime('2021-03-01 00:00:00'));
复制代码


因为 index_granularity 设置为 4,所以每 4 条数据就会生成一条索引记录,即使用插入的第 1、5、9 条数据 id 字段的值生成索引文件记录。


2.3.3 标记文件

mrk 标记文件在 primary.idx 索引文件和 bin 数据文件之间起到了桥梁作用。primary.idx 文件中的每条索引在 mrk 文件中都有对应的一条记录。一条记录的组成包括:


  • offset-compressed bin file

  • 表示指向的压缩数据块在 bin 文件中的偏移量。

  • offset-decompressed data block

  • 表示指向的数据在解压数据块中的偏移量。

  • row counts

  • 代表数据记录行数,小于等于 index_granularity 所设置的值。



索引,标记和数据文件下图所示:



作者:TalkingData 张凯


参考文档:


1.https://clickhouse.tech/docs

2.http://www.clickhouse.com.cn/topic/5ffec51eba8f16b55dd0ffe4

3.《ClickHouse 原理解析与应用实践》(机械工业出版社出版,作者朱凯)


本文转载自公众号 TalkingData(ID:Talkingdata)。


原文链接


ClickHouse核心引擎MergeTree解读

2021-04-07 10:056592

评论 1 条评论

发布
用户头像
这个版本是多少的?我本地的不会有每个列一个bin文件的。我的版本是:ClickHouse server version 21.1.2.15 (official build).
2021-04-07 19:23
回复
没有更多了
发现更多内容

复旦大学附属中山医院:利用明道云进行风险管理及器械溯源的实践案例分享

明道云

基于低代码平台可视化搭建应用

这我可不懂

低代码 JNPF 可视化搭建

万物互联时代,互联网企业为什么需要华为云网站安全解决方案?

平平无奇爱好科技

一文让你从零开始入门 K8s

伤感汤姆布利柏

看北京地铁如何利用数智底座充分发挥数据价值

用友BIP

数智底座

DevOps|从腾讯TEG CDC解散聊技术中台价值和建设

laofo

DevOps 研发效能 技术中台 组织建设

Maxon Rugged Industrial Explosion-Proof IP68 WiFi 6 Series in hazardous areas.

wifi6module

Wi-Fi 6 Explosion-proof ip68 industrial IIC T6

保姆级教程:带你体验华为云测试计划CodeArts TestPlan

华为云开发者联盟

云计算 华为云 华为云开发者联盟 企业号 7 月 PK 榜

提高网站可用性需要真家伙,华为云网站高可用解决方案有何亮点?

平平无奇爱好科技

5年经验,不会Java性能优化,面试原地翻车

程序员小毕

程序员 后端 JVM java面试 Java性能优化

拥抱创新 争创一流 酷克数据入选北京市“专精特新中小企业”

HashData

华为扫地僧:揭秘IoT+鸿蒙帮助企业突围物联网安全问题

华为云开发者联盟

物联网 华为云 华为云开发者联盟 企业号 7 月 PK 榜

揭秘!用友BIP多维数据库:企业数智化的国产利器

用友BIP

推荐6款开源免费工具

伤感汤姆布利柏

分布式服务一篇概览

这我可不懂

分布式

九章云极发布大模型时代下全新产品系列 ,逐浪算力x软件万亿级市场|TE洞察

TE智库

开源 大模型 AIGC

SpringBoot——自定义自动配置与起步依赖

互联网工科生

spring springboot

中移物联车联网项目,在 TDengine 3.0 的应用

爱倒腾的程序员

涛思数据 tdengine 时序数据库

分享6款常用的开源工具(白嫖党入)

树上有只程序猿

华为云专家出品《字节码编程指南》电子书上线

华为云PaaS服务小智

云计算 字节码编程 华为云

游戏和电商企业活动频繁,华为云网站安全解决方案如何促进业务发展和增长

平平无奇爱好科技

分享6个数据可视化软件工具

互联网工科生

数据可视化 可视化软件

国产软件崛起,用友引领企业数智化转型新风向

用友BIP

国产替代

第十八届研电赛“安谋科技杯”上海赛区决赛成功举办

脑极体

AI

万字血书Vue—Vue语法

不在线第一只蜗牛

Vue 教程 语法

低代码应用开发平台 高效构建业务系统

力软低代码开发平台

自动化流行于虚拟制作行业,Perforce推出免费API助力

龙智—DevSecOps解决方案

ci API Helix Core 虚拟制作

如何克服嵌入式开发中的各种挑战,构建完善工具链并落地最佳实践?

龙智—DevSecOps解决方案

嵌入式 嵌入式开发

MAYA 2024和之前版本相比有哪些变化?

Finovy Cloud

  • 扫码添加小助手
    领取最新资料包
ClickHouse核心引擎MergeTree解读_开源_TalkingData_InfoQ精选文章