首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ClickHouse各种MergeTree的关系与作用

ClickHouse各种MergeTree的关系与作用

作者头像
Nauu
发布于 2020-03-25 18:56:03
发布于 2020-03-25 18:56:03
8.8K00
代码可运行
举报
运行总次数:0
代码可运行

ClickHouse的整个体系里面,MergeTree表引擎绝对是一等公民,使用ClickHouse就是在使用MergeTree,这种说法一点也不为过。

众所周知,MergeTree表引擎是一个家族系列,目前整个系列一共包含了14种不同类型的MergeTree,可谓是功能丰富了吧?

但凡事都有两面性,功能丰富的同时也无疑让很多朋友犯了难。

这么多表引擎,它们之间是什么关系?

我们到底应该使用哪一种表引擎?

今天我就用这篇文章,尝试回答上述两个高频问题。

老师常教导我们要训练结构化思维,通过抽象、归纳等办法来分析一个事物,有时候会起到事半功倍的效果。


这么多表引擎,它们之间是什么关系?

我们可以使用两种关系,来理解整个MergeTree系列:

  • 继承关系

首先,为了便于理解,可以使用继承关系来看待MergeTree。通过最基础的MergeTree表引擎,向下派生出6个变种表引擎,如下图所示

在ClickHouse底层具体的实现方法中,上述7种表引擎的区别主要体现在Merge合并的逻辑部分。如下图所示,是我简化后的对象关系:

可以看到,在具体的实现逻辑部分,7种MergeTree共用一个主体,在触发Merge动作时,调用了各自独有的合并逻辑。

而除开MergeTree之外的其他6个变种表引擎,它们的Merge合并逻辑,全部是建立在MergeTree基础之上的,如下图所示:

它们均继承于MergeTree的 MergingSortedBlockInputStream。

MergingSortedBlockInputStream 的主要作用,是按照ORDER BY的规则保持新分区数据的有序性。

而其他6种变种MergeTree的合并逻辑,则是在有序的基础之上 "各有所长",要么是将排序后相邻的重复数据消除、亦或是将它们累加汇总。

所以,从继承关系的角度来理解,我们不仅明白了这7种MergeTree的关系,也进一步明确了一个事实,它们的主要区别在Merge部分的逻辑,所以特殊功能只会在Merge合并时才会触发。

  • 组合关系

刚才已经介绍了7种MergeTree的关系,余下的7种是ReplicatedMergeTree系列。

ReplicatedMergeTree与普通的MergeTree又有什么区别呢? 我们接着看下面这张图:

图中的虚线框部分是MergeTree的能力边界,而ReplicatedMergeTree在它的基础之上增加了分布式协同的能力。

借助ZooKeeper的消息日志广播,实现了副本实例之间的数据同步功能。

ReplicatedMergeTree系列可以用组合关系来理解,如下图所示:

当我们为7种MergeTree加上Replicated前缀后,又能组合出7种新的表引擎,这些ReplicatedMergeTree拥有副本协同的能力。


我们到底应该使用哪一种表引擎?

现在回答第二个问题,按照使用的场景划分,可以将上述14种表引擎大致分成以下6类应用场景:

  • 默认情况

在没有特殊要求的场合,使用基础的MergeTree表引擎即可,它不仅拥有高效的性能,也提供了所有MergeTree共有的基础功能,包括列存、数据分区、分区索引、一级索引、二级索引、TTL、多路径存储等等。

与此同时,它也定义了整个MergeTree家族的基调,例如:

ORDER BY 决定了每个分区中数据的排序规则;

PRIMARY KEY 决定了一级索引(primary.idx);

ORDER BY 可以指代PRIMARY KEY, 通常只用声明ORDER BY 即可。

接下来将要介绍的其他表引擎,除开ReplicatedMergeTree系列外,都是在Merge合并动作时添加了各自独有的逻辑。

  • 数据去重

通过刚才的说明,大家应该明白,MergeTree的主键(PRIMARY KEY)只是用来生成一级索引(primary.idx)的,并没有唯一性约束这样的语义。

一些朋友在使用MergeTree的时候,用传统数据库的思维来理解MergeTree就会出现问题。

如果业务上不允许数据重复,遇到这类场景就可以使用ReplacingMergeTree,如下图所示:

ReplacingMergeTree通过ORDER BY,表示判断唯一约束的条件。当分区合并之时,根据ORDER BY排序后,相邻重复的数据会被排除。

由此,可以得出几点结论:

第一,使用ORDER BY作为特殊判断标识,而不是PRIMARY KEY。关于这一点网上有一些误传,但是如果理解了ORDER BYPRIMARY KEY的作用,以及合并逻辑之后,都能够推理出应该是由ORDER BY决定。

ORDER BY的作用, 负责分区内数据排序;

PRIMARY KEY的作用, 负责一级索引生成;

Merge的逻辑, 分区内数据排序后,找到相邻的数据,做特殊处理。

第二,只有在触发合并之后,才能触发特殊逻辑。以去重为例,在没有合并的时候,还是会出现重复数据。

第三,只对同一分区内的数据有效。以去重为例,只有属于相同分区的数据才能去重,跨越不同分区的重复数据不能去重。

上述几点结论,适用于包含ReplacingMergeTree在内的6种MergeTree,所以后面不在赘述。

  • 预聚合(数据立方体)

有这么一类场景,它的查询主题是非常明确的,也就是说聚合查询的维度字段是固定,并且没有明细数据的查询需求,这类场合就可以使用SummingMergeTree或是AggregatingMergeTree,如下图所示:

可以看到,在新分区合并后,在同一分区内,ORDER BY条件相同的数据会进行合并。如此一来,首先表内的数据行实现了有效的减少,其次度量值被预先聚合,进一步减少了后续计算开销。

聚合类MergeTree通常可以和表引擎协同使用,如下图所示:

可以将物化视图设置成聚合类MergeTree,将其作为固定主题的查询表使用。

值得一提的是,通常只有在使用SummingMergeTree或AggregatingMergeTree的时候,才需要同时设置ORDER BYPRIMARY KEY。

显式的设置PRIMARY KEY,是为了将主键和排序键设置成不同的值,是进一步优化的体现。

例如某个场景的查询需求如下:

聚合条件,GROUP BY A,B,C

过滤条件,WHERE A

此时,如下设置将会是一种较优的选择:

GROUP BY A,B,C

PRIMARY KEY A

BTW,如果ORDER BYPRIMARY KEY不同,PRIMARY KEY必须是ORDER BY的前缀(为了保证分区内数据和主键的有序性)。

  • 数据更新

数据的更新在ClickHouse中有多种实现手段,例如按照分区Partition重新写入、使用Mutation的DELETE和UPDATE查询。

使用CollapsingMergeTree或VersionedCollapsingMergeTree也能实现数据更新,这是一种使用标记位,以增代删的数据更新方法,如下图所示:

通过增加一个标志字段(例如图中的sigh字段),作为数据有效性的判断依据。

可以看到,在新分区合并后,在同一分区内,ORDER BY条件相同的数据,其标志值为1和-1的数据行会进行抵消。

下图是另外一种便于理解的视角,就如同挤压瓦楞纸一般,数据被抵消了:

CollapsingMergeTree和VersionedCollapsingMergeTree的区别又是什么呢?

CollapsingMergeTree对数据写入的顺序是敏感的,它要求标志位需要按照正确的顺序排序。例如按照1,-1的写入顺序是正确的; 而如果按照-1,1的错误顺序写入,CollapsingMergeTree就无法正确抵消。

试想,如果在一个多线程并行的写入场景,我们是无法保证这种顺序写入的,此时就需要使用VersionedCollapsingMergeTree了。

VersionedCollapsingMergeTree在CollapsingMergeTree基础之上,额外要求指定一个version字段,在分区Merge合并时,它会自动将version字段追加到ORERY BY的末尾,从而保证了标志位的有序性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ENGINE = VersionedCollapsingMergeTree(sign,ver)ORDER BY id//等效于ORDER BY id,ver
  • 监控集成

GraphiteMergeTree可以与Graphite集成,如果你使用了Graphite作为系统的运行监控系统, 则可以通过GraphiteMergeTree存储指标数据,加速查询性能、降低存储成本。

  • 高可用

Replicated* 拥有数据副本的能力,如下图所示:

结合刚才的5类场景,如果进一步需要高可用的需求,选择一种MergeTree和Replicated组合即可,例如ReplicatedMergeTree、ReplicatedReplacingMergeTree等等。

读完这篇文章,你是否对ClickHouse的MergeTree家族有了更深刻的认识呢?如果仍有疑问,欢迎观看我在腾讯云做的ClickHouse科普直播,地址如下:

ClickHouse的前世今生-直播回放

在视频中我也专门介绍了ClickHouse的表引擎部分。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ClickHouse的秘密基地 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python 实战:字符统计程序
Python 是一门易于学习且功能强大的编程语言,被广泛应用于各个领域。本篇文章将介绍一个基础的 Python 实战案例,通过编写一个简单的字符统计程序来帮助我们学习 Python 的基本语法和字符串操作。
剑指工控
2024/03/20
2560
Python 实战:字符统计程序
五道基础且高频的Python算法面试题
编写一个函数,计算斐波那契数列中第 n 个数字的值。斐波那契序列从 0 和 1 开始,后续每个数字都是前两个数字的和。
周辰晨
2024/04/22
2060
【Python 千题 —— 算法篇】重复字符查找
在处理字符串时,我们经常需要分析字符的频率,找出那些出现次数超过一次的重复字符。这在数据处理、文本分析、密码学等多个领域都有广泛的应用。比如,在字符串中找出重复的字符,可以帮助我们发现数据的规律性或错误信息,甚至可以用于密码破解或压缩算法的设计。
繁依Fanyi
2024/09/06
1740
LeetCode 151:给定一个字符串,逐个翻转字符串中的每个单词
Given an input string, reverse the string word by word.
爱写bug
2019/07/11
2.5K0
Java判断一个字符串是否包含某个字符
在Java编程中,字符串操作是日常开发中非常频繁的活动之一。字符串是文本数据的基本单位,它们可以包含字母、数字、符号和空格等字符。对字符串进行操作,如判断、查找、替换、拆分等,是编程中常见的任务。在很多应用场景中,如文本处理、数据验证、用户输入处理等,都需要用到字符串操作。
王也518
2024/04/25
4860
LeetCode 151:给定一个字符串,逐个翻转字符串中的每个单词 Reverse Words in a String
Given an input string, reverse the string word by word.
爱写bug
2019/08/01
1.3K0
解锁 Python 嵌套字典的奥秘:高效操作与实战应用指南
在Python编程中,字典(dict)是一种非常重要的数据结构,它允许我们通过键(key)来快速查找、添加、更新和删除值(value)。字典的键必须是唯一的,而值则可以是任何数据类型,包括数字、字符串、列表、元组甚至是另一个字典。这种灵活性使得字典成为处理复杂数据结构的强大工具。本文将详细介绍Python中字典的定义、基本操作、嵌套字典、遍历方法、高级操作技巧等,并通过代码实例进行演示和分析。
suye
2024/10/16
5480
#2 判断一个字符串是否包含重复字符
判断一个字符串是否包含重复字符。例如:“good”就包含重复字符‘o’,而“abc”就不包含重复字符
py3study
2020/01/17
2.1K0
Java数据结构和算法总结-字符串相关高频面试题算法
前言:周末闲来无事,在七月在线上看了看字符串相关算法的讲解视频,收货颇丰,跟着视频讲解简单做了一下笔记,方便以后翻阅复习同时也很乐意分享给大家。什么字符串在算法中有多重要之类的大路边上的客套话就不多
codingblock
2017/12/28
1.3K0
2025-07-03:使字符频率相等的最少操作次数。用go语言,给定一个字符串 s。 如果某个字符串 t 中所有字符的出现次数相
2025-07-03:使字符频率相等的最少操作次数。用go语言,给定一个字符串 s。
福大大架构师每日一题
2025/07/03
750
2025-07-03:使字符频率相等的最少操作次数。用go语言,给定一个字符串 s。 如果某个字符串 t 中所有字符的出现次数相
给你一些字符串,查找常用字符
https://leetcode-cn.com/problems/find-common-characters/
代码随想录
2021/06/17
4710
2024-07-10:用go语言,给定一个字符串数组words,其中包含一些字符串。可以通过任意次数的操作来交换字符串中的字符。
2024-07-10:用go语言,给定一个字符串数组words,其中包含一些字符串。可以通过任意次数的操作来交换字符串中的字符。每次操作可选两个位置上的字符进行交换。问经过操作后,数组中最多可以形成多少个回文串。
福大大架构师每日一题
2024/08/16
1990
2024-07-10:用go语言,给定一个字符串数组words,其中包含一些字符串。可以通过任意次数的操作来交换字符串中的字符。
2025-05-19:找到初始输入字符串Ⅰ。用go语言,Alice 在电脑上输入一个字符串时,可能会因为按键时间过长,导致某个字
2025-05-19:找到初始输入字符串Ⅰ。用go语言,Alice 在电脑上输入一个字符串时,可能会因为按键时间过长,导致某个字符被重复输入多次。尽管她尽力避免犯错,但最终的输入结果最多只有一次此类重复错误。
福大大架构师每日一题
2025/05/19
780
2025-05-19:找到初始输入字符串Ⅰ。用go语言,Alice 在电脑上输入一个字符串时,可能会因为按键时间过长,导致某个字
LeetCode字符串高频题目整理(持续更新中)
  给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
嵌入式与Linux那些事
2021/05/20
1.4K0
java将字符串分段输出_java输入字符串并将每个字符输出的方法[通俗易懂]
public static void main(String[] args){
全栈程序员站长
2022/11/02
4.1K0
2023-11-29:用go语言,给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。 需保证 返回结果的
2023-11-29:用go语言,给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。
福大大架构师每日一题
2023/11/30
3720
2023-11-29:用go语言,给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。 需保证 返回结果的
leetcode之字符串压缩
这里维护前一个字符及其count的字段,之后从第二个字符开始遍历,判断与前一个字符是否相等,相等则累加,不相等则将该字符的压缩添加到结果中,最后再将最后一个字符的压缩添加到结果中。
code4it
2020/11/02
6090
leetcode之字符串压缩
这里维护前一个字符及其count的字段,之后从第二个字符开始遍历,判断与前一个字符是否相等,相等则累加,不相等则将该字符的压缩添加到结果中,最后再将最后一个字符的压缩添加到结果中。
code4it
2020/10/23
1.2K0
leetcode之字符串压缩
2024-09-21:用go语言,给定一个字符串 s,字符串中的每个字符要么是小写字母,要么是问号‘?‘。对于一个仅包含小写字母
2024-09-21:用go语言,给定一个字符串 s,字符串中的每个字符要么是小写字母,要么是问号'?'。对于一个仅包含小写字母的字符串t,我们定义cost(i)为在t的前i个字符中与t[i]相同的字符的出现次数。字符串 t 的分数是所有位置i的cost(i)之和。现在的任务是用小写字母替换所有的问号'?',使得字符串s的分数最小。如果有多个替换方案使得分数最小,那么返回字典序最小的一个。输入:s = "???"。输出:"abc"。解释:这个例子中,我们将 s 中的问号 '?' 替换得到 "abc" 。对于字符串 "abc" ,cost(0) = 0 ,cost(1) = 0 和 cost(2) = 0 。"abc" 的分数为 0 。其他修改 s 得到分数 0 的字符串为 "cba" ,"abz" 和 "hey" 。这些字符串中,我们返回字典序最小的。
福大大架构师每日一题
2024/09/23
1480
2024-09-21:用go语言,给定一个字符串 s,字符串中的每个字符要么是小写字母,要么是问号‘?‘。对于一个仅包含小写字母
2023-04-13:给定一个字符串数组strs,其中每个字符串都是小写字母组成的, 如果i < j,并且strs[i]和strs[j]所有的字符随意去排列能组
2023-04-13:给定一个字符串数组strs,其中每个字符串都是小写字母组成的,
福大大架构师每日一题
2023/04/13
5200
2023-04-13:给定一个字符串数组strs,其中每个字符串都是小写字母组成的, 如果i < j,并且strs[i]和strs[j]所有的字符随意去排列能组
推荐阅读
Python 实战:字符统计程序
2560
五道基础且高频的Python算法面试题
2060
【Python 千题 —— 算法篇】重复字符查找
1740
LeetCode 151:给定一个字符串,逐个翻转字符串中的每个单词
2.5K0
Java判断一个字符串是否包含某个字符
4860
LeetCode 151:给定一个字符串,逐个翻转字符串中的每个单词 Reverse Words in a String
1.3K0
解锁 Python 嵌套字典的奥秘:高效操作与实战应用指南
5480
#2 判断一个字符串是否包含重复字符
2.1K0
Java数据结构和算法总结-字符串相关高频面试题算法
1.3K0
2025-07-03:使字符频率相等的最少操作次数。用go语言,给定一个字符串 s。 如果某个字符串 t 中所有字符的出现次数相
750
给你一些字符串,查找常用字符
4710
2024-07-10:用go语言,给定一个字符串数组words,其中包含一些字符串。可以通过任意次数的操作来交换字符串中的字符。
1990
2025-05-19:找到初始输入字符串Ⅰ。用go语言,Alice 在电脑上输入一个字符串时,可能会因为按键时间过长,导致某个字
780
LeetCode字符串高频题目整理(持续更新中)
1.4K0
java将字符串分段输出_java输入字符串并将每个字符输出的方法[通俗易懂]
4.1K0
2023-11-29:用go语言,给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。 需保证 返回结果的
3720
leetcode之字符串压缩
6090
leetcode之字符串压缩
1.2K0
2024-09-21:用go语言,给定一个字符串 s,字符串中的每个字符要么是小写字母,要么是问号‘?‘。对于一个仅包含小写字母
1480
2023-04-13:给定一个字符串数组strs,其中每个字符串都是小写字母组成的, 如果i < j,并且strs[i]和strs[j]所有的字符随意去排列能组
5200
相关推荐
Python 实战:字符统计程序
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验