ClickHouse学习笔记(三):MergeTree 原理解析

文章目录

  • 1、简介
  • 2、MergeTree 创建方式与存储结构
    • 2.1、MergeTree 的创建方式
    • 2.2、MergeTree 的存储结构
  • 3、MergeTree 数据分区
    • 3.1、分区目录的命名规则
    • 3.2、分区目录合并过程
  • 4、一级索引
    • 4.1、索引粒度
    • 4.2、索引生成
    • 4.3、索引查询
  • 5、二级索引
  • 6、数据存储
  • 7、数据标记
  • 8、协同总结
    • 8.1、写入过程
    • 8.2、查询过程
    • 8.3、数据标记与压缩块对应关系

1、简介

    ClickHouse 有很多表引擎,而在众多的表引擎中,又属合并树(MergeTree)表引擎及其家族系列(*MergeTreee)最为强大,在生产环境的绝大部分场景中,都会使用此系列的表引擎。合并树表引擎家族如下图所示:
合并树表引擎家族

2、MergeTree 创建方式与存储结构

    MergeTree 在写入一批数据时,数据总会以数据片段的形式写入磁盘,且数据片段不可修改。ClickHouse 会通过后台线程,定期合并这些数据片段,属于相同分区的数据片段会被合成一个新的片段。这种数据片段往复合并的特点,也正是合并数据名称的由来。

2.1、MergeTree 的创建方式

CREATE TABLE table_name (
	...字段省略
) ENGINE = MergeTree()
[PARTITION BY xx]
[ORDER BY xx]
[PRIMARY KEY xx]
[SAMPLE BY xx]
[SETTINGS name=value]

(1)PARTITION BY [选填]:分区键,用于指定表数据以何种标准进行分区。
(2)ORDER BY [必填]:排序键,用于指定在一个数据片段内,数据以何种标准排序。默认情况下主键(PRIMARY KEY)与排序键相同。排序字段既可以是单个列字段,也可以通过元组的形式使用多个列字段,顺序以ORDER BY 后面的字段先后顺序来排序。
(3)PRIMARY BY [选填]:主键,顾名思义,声明后会依照主键字段生成以及索引,用于加速表查询。
(4)SAMPLE BY [选填]:抽样表达式,用于声明数据以何种标准进行采样。
(5)SETTINGS:index_granularity [选填]:index_granularity 对于 MergeTree 而言是一项非常重要的参数,他表示索引的粒度,默认值为 8192。也就是说,MergeTree 的索引在默认情况下,每间隔 8192 行数据才生成一条索引,具体声明方式如下所示:

CREATE TABLE table_name (
	...字段省略
) ENGINE = MergeTree()
... 信息省略
SETTINGS index_granularity=8192;

(6)SETTINGS:index_granularity_bytes [选填]:index_granularity_bytes 每一批次写入数据的体量大小,自适应间隔大小,根据每一批次写入数据的体量大小,动态划分间隔大小,默认为 10M(10*1024*1024)。

2.2、MergeTree 的存储结构

    MergeTree 表引擎中的数据是拥有物理存储的,数据会按照分区目录的形式保存到磁盘之上,其完整的存储结果如下所示:
MergeTree 在磁盘上的物理存储结构
一张数表的完整物理结构分3个层级,依次是数据表目录、分区目录及各分区下具体的额数据文件。
(1)partition:分区目录,余下各类数据文件都是以分区目录的形式被组织存放的,属于相同分区的数据,最终会被合并到同一个分区目录。
(2)checksum.txt:校验文件,使用二进制格式存储。它保存了各类文件(primary.idx、count.txt等)的 size 大小及 size 的哈希值,用于快速检验文件的完整性和正确性。
(3)columns.txt:列信息文件
(4)count.txt:计数文件,记录当前数据分区目录下数据总行数。
(5)primary.idx:一级索引文件,用于存放稀疏索引。
(6)[Column].bin:数据文件,使用压缩格式存储,默认为 LZ4 压缩格式,用于存储某一列数据。多个列就有多个 .bin 文件
(7)[Column].mrk:列字段标记文件,标记文件中保存了 .bin 文件中数量的偏移量信息。首先通过 primary.idx 找到对应数据偏移量,然后再通过偏移量直接从 .bin 中读取数据。.mrk 标记文件和 .bin 文件一一对应。
(8)[Column].mrk2: 如果使用了自适应大小的索引间隔,则标记文件会以 .mrk2 命名,作用原理和 .mrk 一样。
(9)partition.dat 与 minmax_[Column].idx: 用了分区键会产生,partition.dat 用于保存当前分区下分区表大师最终生成的值;minmax 索引用于记录当前分区下分区字段对应原始数据的最小和最大值,查询的时候可快速跳过不必要的分区目录,减少数据扫描范围。
(10)skp_idx_[Column].idx 与 skp_idx_[Column].mrk: 如果建表语句中声明了二级索引,则会额外生成相应的二级索引与标记文件。二级索引又称跳数索引。

3、MergeTree 数据分区

3.1、分区目录的命名规则

命名公式与样式数据的对照关系
**(1)PartitionID:**分区ID,这里是具体的日期。
**(2)MinBlockNum 和 MaxBlockNum:**最小数据块编号与最大数据块编号。计数在单张 MergeTree 数据表内全局累加。
**(3)Level:**合并的层级,相同分区发生合并,则相应分区内计数累计加1。

3.2、分区目录合并过程

分区合并过程
(1)MergeTree 分区目录不是在数据表创建后就存在的,而是在数据写入过程中被创建的。
(2)伴随着每一批数据的写入,MergeTree 都会生成一批新的分区目录

4、一级索引

4.1、索引粒度

稀疏索引
稀疏索引的优势在于使用少量的索引标记就能够记录大量数据的区间位置信息,而且数据量越大优势越为明显。

4.2、索引生成

索引生产
上面的例子是拿(CounterID+EventDate)作为主键生成的索引。

4.3、索引查询

(1)生成查询条件区间:首先,将查询条件转换为条件区间。一个具体的数据段是一个 MarkRange,划分依据是间隔(默认8192)
(2)递归交际判断:以递归的形式,依次对 MarkRange 的数据区间与条件区间做交集判断。
(3)合并 MarkRange 区间:将最终匹配的 MarkRange 聚合在一起,合并它们的范围。
索引查询

5、二级索引

    MergeTree 支持二级索引,二级索引又称跳数索引,由数据的聚合信息构建而成,目的也是帮助查询减少数据的扫描范围。
index_granularity:按照设置的粒度值的大小将数据分成 n 段,总共有 [0, n-1] 个区间(n=total_rows/index_granularity)。
granularity:定义了一行跳数索引能够跳过多少个 index_granularity 区间的数据。

跳数索引

6、数据存储

  • 数据按列存储,具体到每一列数据也是独立存储的,每个列字段都拥有一个与之对应的.bin数据文件;
  • 数据写入之前是经过压缩的,目前支持 LZ4、ZSTD、Multiple 和 Delta 几种算法,默认使用 LZ4 算法;
  • 数据会事先依照 ORDER BY 的声明排序,最后以压缩数据块的形式被组织并写入 .bin 文件中。

压缩数据块示意图:
压缩数据块示意图

    MergeTree 在数据具体的写入过程中,会依照索引粒度(默认情况下,每次取 8192 行),按批次获取数据并处理。如果把一批数据的未压缩大小设置为 size,切割过程则如下图所示。

切割压缩数据块的逻辑示意图:

在 .bin 文件中引入压缩数据块的目的:
(1) 数据压缩后可以有效减少数据大小,但是数据压缩解压会带来性能损耗,控制压缩数据的大小以求在性能损耗和压缩率之间寻求一种平衡
(2)读取数据文件的时候可以不用读取整个 .bin 文件,缩小数据读取的范围。

7、数据标记

  • 数据标记根据便宜读取赌赢的压缩数据块
  • 以 index_granularity 粒度加载特定的一小段

(1)通过索引下标编号找到对应的数据标记:
通过索引下标编
(2)标记数据示意图
标记数据

(3)JavaEnable 字段的标记文件和压缩文件的对应关系:
对应关系

提问:在 .mrk 文件中,第 0 个压缩数据块的截止偏移量是 12016 ,在 .bin 数据文件中第 0 个压缩数据块的压缩大小是 12000 为什么不一样呢?
答:一个完整的是压缩数据块是由头信息加上压缩数据组成的,它的头信息由 9 个字节组成,压缩后大小是 8 个字节。所以,8 + 12000 + 8 = 12016。

8、协同总结

8.1、写入过程

(1)生成分区目录,写入第一批数据;
(2)相同分区的目录依照规则合并到一起;
(3)按照 index_granularity 索引粒度生成 primary.idx 一级索引、二级索引、每一列的 .mrk 数据标记、.bin压缩文件。

分区目录、索引、标记和压缩数据的生成过程示意图:
写入

8.2、查询过程

(1)依次借助分区索引、一级索引、二级索引,将数据扫描范围缩至最小;
(2)借助数据标记将需要解压与计算的数据范围缩小至最小;

将扫描数据范围最小化的过程:
查询

8.3、数据标记与压缩块对应关系

  • 多对一、一对一关系比较好理解
  • 一个标记对应多个压缩块(一对多),说明 index_granualarity 间隔的数据很大。

多个数据标记对应同一个压缩块的示意图:
多对一

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/4962.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

BootStrap4:栅格系统

1、container容器 container:固定宽度的容器container-fluid:响应式容器 2、栅格选项 Bootstrap4 总共有五个栅格等级,每个响应式分界点隔出一个等级 Ps:.row上带有margin-left: -15px;margin-right: -15px;属性,你…

【22年蓝桥杯】十三届蓝桥杯真题JavaB组解析+代码(带你复习知识点)(一)

试题 A: 星期计算 【填空题】 答案:7 解析:直接对所给数进行取余,然后直接再加6(注意:不能直接让20^226再对7进行取余操作,这是不对的,这个6可以看成已经取余过了。) 直接取余的话可…

Linux系统安装部署及配置Grafana

TOC 用于 UI 展示 wget https://dl.grafana.com/oss/release/grafana-8.0.3-1.x86_64.rpm1 安装 grafana 1.1 下载安装 wget https://dl.grafana.com/oss/release/grafana-8.0.3-1.x86_64.rpmsudo yum install grafana-8.0.3-1.x86_64.rpm1.2 启动&状态查看 sudo syst…

PHP初级教程------------------(3)

目录 文件包含 文件包含的作用 文件包含四种形式 文件加载原理 Include和require区别 文件加载路径 文件嵌套包含 函数 函数的基本概念 函数定义语法 函数命名规范 参数详解 形参 实参 默认值 引用传递 函数体 函数返回值 ​作用域 静态变量 可变函数 匿名函数 闭包 伪类型 文件…

作为一个数学专业的学生,我是怎么看待编程的?

1.概况 博主的专业是数学与应用数学,简称应数。虽然后面跟了个应用数学,但是这个专业应该是本科阶段最接近数学的专业了。我认为这个专业使我具有如下的几个优势: 数学的学习使我具有较强的思维能力。编程本质上就是通过写代码的方式来解决…

大数据Flink进阶(八):Apache Flink架构介绍

Apache Flink架构介绍 一、Flink组件栈 在Flink的整个软件架构体系中,同样遵循这分层的架构设计理念,在降低系统耦合度的同时,也为上层用户构建Flink应用提供了丰富且友好的接口。

山东大学机器学习大作业

数据处理与可视化这里是DLRM模型数据集预处理模块:args.ln_emb ln_emb.tolist() m_spa args.arch_sparse_feature_sizeln_emb np.asarray(ln_emb)num_fea ln_emb.size 1 # num sparse num dense featuresm_den_out ln_bot[ln_bot.size - 1]Sparse fea 26, D…

Java设计模式-3、单例模式

单例模式 单例模式属于创建型模式,⼀个单例类在任何情况下都只存在⼀个实例, 构造⽅法必须是私有的、由⾃⼰创建⼀个静态变量存储实例,对外提供⼀ 个静态公有⽅法获取实例。 优点是内存中只有⼀个实例,减少了开销,尤…

代码随想录|day26|回溯算法part03● 39. 组合总和● 40.组合总和II● 131.分割回文串

今天的练习基本就是回溯法组合问题,这一节只要看labuladong即可。 组合问题: 39. 组合总和---------------------形式三,元素无重可复选 链接:代码随想录 一次对,同样在进入下次循环时,注意startindex是从j…

欧莱雅校招负责人张泽宇:拥抱Z世代,探索新玩法

作为校招HR,你在雇主品牌创新实践的路上做过什么尝试? 2020年,欧莱雅正式推出了全新的雇主品牌价值主张 —— 敢为敢超越,就是欧莱雅(Freedom to go beyond, thats the beauty of L’ORAL),鼓励…

使用ChatGPT进行AI对话

1.ChatGPT简介 ChatGPT是美国人工智能研究实验室OpenAI新推出的一种人工智能技术驱动的自然语言处理工具,使用了Transformer神经网络架构,也是GPT-3.5架构,这是一种用于处理序列数据的模型,拥有语言理解和文本生成能力&#xff0c…

C/C++ 日期 时间 函数总结

使用C标准库 有四个与时间相关的类型&#xff1a;clock_t、time_t、size_t 和 tm。类型 clock_t、size_t 和 time_t 能够把系统时间和日期表示为某种整数 头文件 #include <time.h> #include <stdio.h> tm 结构: struct tm {int tm_sec; // 秒&#xff0c;…

隐私计算-TEE执行环境

一、TEE 的定义 论述完 TEE 的概念后&#xff0c;接下来进一步解析 TEE 的深层定义。目前对于 TEE 的定义有很多种形式&#xff0c;针对于不同的安全性需求和平台&#xff0c;TEE 的定义也不尽相同&#xff0c;但在所有 TEE 的定义中都会包含两个最关键的点&#xff1a;独立执…

谈谈分布式一致性机制

分布式中一致性是非常重要的&#xff0c;分为弱一致性和强一致性。 现在主流的一致性协议一般都选择的是弱一致性的特殊版本&#xff1a;最终一致性。下面就从分布式系统的基本原则讲起&#xff0c;再整理一些遵循这些原则的协议或者机制&#xff0c;争取通俗易懂。 但是要真…

【通过代理监听UIScrollView的滚动事件 Objective-C语言】

一、输出,当UIScrollView滚动的时候,实时输出当前UIScrollView滚动的位置, 1.用代理实现吧, contentOffset,代表偏移吧,我需要你当UIScrollView滚动的时候,实时输出UIScrollView滚动的位置, 2.第一,我们如何获得UIScrollView滚动的位置呢,contentOffset,是不是就是…

【创作赢红包】LeetCode:232. 用栈实现队列

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340;算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 一、&#x1f331;232. 用栈实现队列 题目描述&#xff1a;请你仅使用两个栈实现先入先出队…

【论文速递】ACL 2022 - 查询和抽取:将事件抽取细化为面向类型的二元解码

【论文速递】ACL 2022 - 查询和抽取&#xff1a;将事件抽取细化为面向类型的二元解码 【论文原文】&#xff1a;Query and Extract: Refining Event Extraction as Type-oriented Binary Decoding 【作者信息】&#xff1a;Wang, Sijia and Yu, Mo and Chang, Shiyu and Sun,…

IP地址规划方法

一、IP地址规划的基本步骤&#xff1a; &#xff08;1&#xff09;判断用户对网络以及主机数的需求&#xff1b; &#xff08;2&#xff09;计算满足用户需要的基本网络地址结构&#xff1b; &#xff08;3&#xff09;计算地址掩码&#xff1b; &#xff08;4&#xff09;…

React Three Fiber动画入门

使用静态对象和形状构建 3D 场景非常酷&#xff0c;但是当你可以使用动画使场景栩栩如生时&#xff0c;它会更酷。 在 3D 世界中&#xff0c;有一个称为角色装配的过程&#xff0c;它允许你创建称为骨架的特殊对象&#xff0c;其作用类似于骨骼和关节系统。 这些骨架连接到一块…

2023-03-24:音视频mp3和h264混合(muxer)编码为mp4,用go语言编写。

2023-03-24&#xff1a;音视频mp3和h264混合&#xff08;muxer&#xff09;编码为mp4&#xff0c;用go语言编写。 答案2023-03-24&#xff1a; 这是一个使用FFmpeg库将MP3和H.264混合编码为MP4的Go语言程序。程序的大体过程如下&#xff1a; 1.设置FFmpeg库路径和环境变量。…