Clickhouse中支持的Join类型

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
云原生数据仓库AnalyticDB MySQL版,基础版 8ACU 100GB 1个月
简介: 此为Join探索系列的第一篇

ClickHouse是一个开源的面向列的数据库管理系统(DBMS),专为需要在大量数据上进行超低延迟分析查询的用例进行构建和优化。为了实现分析应用的最佳性能,通常会将表合并为一个称为数据去规范化的过程。扁平化的表通过避免连接操作来最小化查询延迟,但会增加增量ETL的复杂性,通常可以接受以换取亚秒级的查询性能。
然而,对于某些工作负载,例如来自传统数据仓库的工作负载,去规范化数据并不总是可行的,有时分析查询的源数据的一部分需要保持规范化。这些规范化的表占用更少的存储空间,并提供了数据组合的灵活性,但对于某些类型的分析需要在查询时进行连接操作。
幸运的是,与一些误解相反,ClickHouse完全支持连接操作!除了支持所有标准的SQL JOIN类型外,ClickHouse还提供了其他适用于分析工作负载和时间序列分析的JOIN类型。ClickHouse允许您在连接执行时选择6种不同的算法(我们将在博客系列的下一部分中详细探讨),或者允许查询规划器根据资源可用性和使用情况在运行时自适应选择和动态更改算法。
在ClickHouse中,即使是对大型表的连接操作也可以实现良好的性能,但这种用例尤其需要用户仔细选择和调整连接算法以适应其查询工作负载。虽然我们预计随着时间的推移,这种过程也会变得更加自动化和启发式驱动,但本博客系列提供了对ClickHouse连接执行内部原理的深入了解,以便您可以为应用程序常用的查询优化连接操作。
在本文中,我们将使用一个规范化的关系数据库示例模式,以演示ClickHouse中可用的不同连接类型。在接下来的文章中,我们将深入了解ClickHouse中可用的6种不同的连接算法。我们将探索ClickHouse如何将这些连接算法集成到其查询流水线中,以尽快执行连接类型。未来的部分将涵盖分布式连接操作。

Test Data and Resources
我们使用Venn图和示例查询来解释ClickHouse中可用的连接类型,这些示例查询基于来自关系数据集存储库的规范化IMDB数据集。
创建和加载表的说明:
Join1.png
上面的4个表中的数据代表movies。一个电影可以有一个或多个genres。电影中的roles由actors扮演。图中的箭头表示外键与主键之间的关系。例如,genres表中一行的movie_id列包含movies表中一行的id值。
movies和actors之间存在多对多的关系。通过使用roles表,将这种多对多的关系规范化为两个一对多的关系。roles表的每一行包含movies表和actors表的id字段的值。

Join types supported in ClickHouse
• INNER JOIN
• OUTER JOIN
• CROSS JOIN
• SEMI JOIN
• ANTI JOIN
• ANY JOIN
• ASOF JOIN

INNER JOIN
join2.png
内连接(INNER JOIN)对于每对在连接键上匹配的行,返回左表行的列值与右表行的列值的组合。如果一行有多个匹配项,则返回所有匹配项(这意味着对于具有匹配的连接键的行,会产生笛卡尔积)。
以下查询通过将movies表与genres表进行连接,找到每部电影的genre(s):
join3.png
请注意,可以省略INNER关键字。使用以下其他连接类型之一,可以扩展或更改INNER JOIN的行为。
图片 4.png
左外连接(LEFT OUTER JOIN)的行为类似于内连接(INNER JOIN),此外对于左表中的非匹配行,ClickHouse会返回右表列的默认值。
右外连接(RIGHT OUTER JOIN)查询类似于左外连接,它还返回右表中非匹配行的值,以及左表列的默认值。
全外连接(FULL OUTER JOIN)查询结合了左外连接和右外连接,它返回左表和右表中非匹配行的值,以及左表和右表列的默认值。
以下查询找出所有没有流派的电影,通过查询movies表中在genres表中没有匹配的所有行,因此在查询时,对于movie_id列会得到默认值0:
图片 5.png
Note that the OUTER keyword can be omitted.

CROSS JOIN
图片 6.png
交叉连接(CROSS JOIN)在不考虑连接键的情况下产生两个表的完全笛卡尔积。左表的每一行都与右表的每一行组合在一起。
因此,下面的查询将movies表的每一行与genres表的每一行组合在一起。
图片 7.png
虽然前面的示例查询本身并没有太多意义,但可以通过使用WHERE子句将匹配的行关联起来,来扩展查询,以实现查找每个movies的genre的内连接行为:
图片 8.png
图片 9.png
一个CROSS JOIN的另一种语法是在FROM子句中用逗号分隔的方式指定多个表。 如果查询的WHERE部分中存在连接表达式,ClickHouse会将CROSS JOIN重写为INNER JOIN。 我们可以通过EXPLAIN SYNTAX来检查示例查询是否符合这种情况(它返回查询在执行之前被重写的语法优化版本):
图片 10.png
在语法优化的交叉JOIN查询版本中,内部JOIN子句包含“ALL”关键字,该关键字是为了保持交叉JOIN的笛卡尔积语义,即使被重写为内部JOIN,因此笛卡尔积可以被禁用。
如上所述,可以省略外部连接,并且可以添加可选的所有关键字,你可以写所有的外部连接,它会正常工作。

(LEFT / RIGHT) SEMI JOIN
图片 11.png
左半连接(LEFT SEMI JOIN)查询返回左表中至少在右表中有一个连接键匹配的行的列值。只返回找到的第一个匹配项(禁用笛卡尔积)。
右半连接(RIGHT SEMI JOIN)查询类似,它返回右表中至少在左表中有一个匹配的行的值,但只返回找到的第一个匹配项。
以下查询找出在2023年参演过电影的所有演员/女演员。请注意,如果使用普通的(INNER)连接,同一个演员/女演员如果在2023年中扮演了多个角色,将会出现多次:
图片 12.png

(LEFT / RIGHT) ANTI JOIN
图片 13.png
左反连接(LEFT ANTI JOIN)返回左表中所有非匹配行的列值。
类似地,右反连接(RIGHT ANTI JOIN)返回右表中所有非匹配行的列值。
我们之前的外连接示例查询的另一种形式是使用反连接来查找数据集中没有genre的movie:
该查询使用左反连接将movies表的id与genres表的movie_id进行连接。它将返回movies表中所有没有与genres表匹配的行,即数据集中没有流派的电影的标题。这样,查询结果将只包含没有流派的电影的标题。
图片 14.png

(LEFT / RIGHT / INNER) ANY JOIN
图片 15.png
左任意连接(LEFT ANY JOIN)是左外连接(LEFT OUTER JOIN)和左半连接(LEFT SEMI JOIN)的组合,意味着ClickHouse将返回左表中每一行的列值,要么与右表中匹配行的列值组合,要么与右表的默认列值组合(如果没有匹配)。如果左表的一行在右表中有多个匹配项,ClickHouse只返回第一个匹配项的组合列值(禁用笛卡尔积)。
类似地,右任意连接(RIGHT ANY JOIN)是右外连接(RIGHT OUTER JOIN)和右半连接(RIGHT SEMI JOIN)的组合。
内任意连接(INNER ANY JOIN)是内连接(INNER JOIN)并禁用了笛卡尔积。
我们使用一个抽象示例和两个临时表(left_table和right_table)来演示左任意连接:
图片 16.png
This is the same query using a RIGHT ANY JOIN:
图片 17.png
This is the query with an INNER ANY JOIN:
图片 18.png

ASOF JOIN
图片 19.png
ASOF JOIN提供了非精确匹配的能力。如果左表中的一行在右表中没有精确匹配,那么将使用最接近的右表行作为匹配。
这在时间序列分析中非常有用,并可以大大降低查询的复杂性。
我们将以股票市场数据的时间序列分析为例。一个quotes表包含了基于每天特定时间的股票符号报价。在我们的示例数据中,价格每10秒更新一次。一个trades表列出了符号的交易 - 在特定时间买入的特定数量的符号:
图片 20.png
为了计算每笔交易的具体成本,我们需要将交易与其最接近的报价时间进行匹配。
使用ASOF JOIN,这个过程非常简单和紧凑,我们可以在ON子句中指定精确匹配条件,并在AND子句中指定最接近匹配条件 - 我们要寻找在交易日期之前或者正好等于交易日期的quotes表中的最接近行:
图片 21.png
图片 22.png

请注意,ASOF JOIN的ON子句是必需的,并且在AND子句的非精确匹配条件旁边指定了一个精确匹配条件。
目前,ClickHouse不支持没有任何连接键部分执行严格匹配的连接(尚未支持)。

Summary
这篇博客文章展示了ClickHouse如何支持所有标准的SQL JOIN类型,以及为支持分析查询而设计的专用JOIN类型。我们描述和演示了所有支持的JOIN类型。
在这个系列的下一部分中,我们将探讨ClickHouse如何将经典的JOIN算法与其查询管道相结合,以尽可能快地执行本文中描述的JOIN类型。

相关文章
|
存储 监控 OLAP
【ClickHouse 技术系列】- 在 ClickHouse 物化视图中使用 Join
本文翻译自 Altinity 针对 ClickHouse 的系列技术文章。面向联机分析处理(OLAP)的开源分析引擎 ClickHouse,因其优良的查询性能,PB级的数据规模,简单的架构,被国内外公司广泛采用。本系列技术文章,将详细展开介绍 ClickHouse。
【ClickHouse 技术系列】- 在 ClickHouse 物化视图中使用 Join
|
2月前
|
存储 关系型数据库 数据库
【DDIA笔记】【ch2】 数据模型和查询语言 -- 多对一和多对多
【6月更文挑战第7天】该文探讨数据模型,比较了“多对一”和“多对多”关系。通过使用ID而不是纯文本(如region_id代替"Greater Seattle Area"),可以实现统一、避免歧义、简化修改、支持本地化及优化搜索。在数据库设计中,需权衡冗余和范式。文档型数据库适合一对多但处理多对多复杂,若无Join,需应用程序处理。关系型数据库则通过外键和JOIN处理这些关系。文章还提及文档模型与70年代层次模型的相似性,层次模型以树形结构限制了多对多关系处理。为克服层次模型局限,发展出了关系模型和网状模型。
37 6
|
2月前
|
XML NoSQL 数据库
【DDIA笔记】【ch2】 数据模型和查询语言 -- 概念 + 数据模型
【6月更文挑战第5天】本文探讨了数据模型的分析,关注点包括数据元素、关系及不同类型的模型(关系、文档、图)与Schema模式。查询语言的考量涉及与数据模型的关联及声明式与命令式编程。数据模型从应用开发者到硬件工程师的各抽象层次中起着简化复杂性的关键作用,理想模型应具备简洁直观和可组合性。
23 2
|
2月前
|
SQL 人工智能 关系型数据库
【DDIA笔记】【ch2】 数据模型和查询语言 -- 文档模型中Schema的灵活性
【6月更文挑战第8天】网状模型是层次模型的扩展,允许节点有多重父节点,但导航复杂,需要预知数据库结构。关系模型将数据组织为元组和关系,强调声明式查询,解耦查询语句与执行路径,简化了访问并通过查询优化器提高效率。文档型数据库适合树形结构数据,提供弱模式灵活性,但在Join支持和访问局部性上不如关系型。关系型数据库通过外键和Join处理多对多关系,适合高度关联数据。文档型数据库的模式灵活性体现在schema-on-read,写入时不校验,读取时解析,牺牲性能换取灵活性。适用于不同类型或结构变化的数据场景。
28 0
|
2月前
|
SQL JSON NoSQL
【DDIA笔记】【ch2】 数据模型和查询语言 -- 关系模型与文档模型
【6月更文挑战第6天】关系模型是主流数据库模型,以二维表形式展示数据,支持关系算子。分为事务型、分析型和混合型。尽管有其他模型挑战,如网状和层次模型,但关系模型仍占主导。然而,随着大数据增长和NoSQL的出现(如MongoDB、Redis),强调伸缩性、专业化查询和表达力,关系模型的局限性显现。面向对象编程与SQL的不匹配导致“阻抗不匹配”问题,ORM框架缓解但未完全解决。文档模型(如JSON)提供更自然的嵌套结构,适合表示复杂关系,具备模式灵活性和更好的数据局部性。
33 0
|
2月前
|
敏捷开发 存储 缓存
【DDIA笔记】【ch1】 可靠性、可扩展性和可维护性 -- 可维护性
【6月更文挑战第4天】本文探讨了Twitter面临的一次发推文引发的巨大写入压力问题,指出用户粉丝数分布是决定系统扩展性的关键因素。为解决此问题,Twitter采用混合策略,大部分用户推文扇出至粉丝主页时间线,而少数名人推文则单独处理。性能指标包括吞吐量、响应时间和延迟,其中高百分位响应时间对用户体验至关重要。应对负载的方法分为纵向和横向扩展,以及自动和手动调整。文章强调了可维护性的重要性,包括可操作性、简单性和可演化性,以减轻维护负担和适应变化。此外,良好设计应减少复杂性,提供预测性行为,并支持未来改动。
33 0
|
2月前
|
缓存 关系型数据库 数据库
【DDIA笔记】【ch1】 可靠性、可扩展性和可维护性 -- 可扩展性
【6月更文挑战第3天】可扩展性关乎系统应对负载增长的能力,但在产品初期过度设计可能导致失败。理解基本概念以应对可能的负载增长是必要的。衡量负载的关键指标包括日活、请求频率、数据库读写比例等。推特的扩展性挑战在于"扇出",即用户关注网络的广度。两种策略包括拉取(按需查询数据库)和推送(预计算feed流)。推送方法在推特案例中更为有效,因为它减少了高流量时的实时计算压力。
29 0
|
2月前
|
存储 消息中间件 缓存
【DDIA笔记】【ch1】 可靠性、可扩展性和可维护性 -- part1 可靠性
【6月更文挑战第2天】本书探讨现代数据系统,阐述其在信息社会中的关键作用,包括数据库、缓存、搜索引擎、流处理、批处理和消息队列等组成部分。随着技术发展,工具如Kafka、Spark和Redis等多功能组件使得系统设计更为复杂。面对可靠性、可扩展性和可维护性的挑战,书中强调了容错和韧性的重要性,区分了硬件故障、软件错误和人为错误,并提出了应对措施。可靠性关乎用户数据、企业声誉和生存,因此是系统设计的核心考量。
36 0
硬件开发笔记(十): 硬件开发基本流程,制作一个USB转RS232的模块(九):创建CH340G/MAX232封装库sop-16并关联原理图元器件
有了原理图,可以设计硬件PCB,在设计PCB之间还有一个协同优先动作,就是映射封装,原理图库的元器件我们是自己设计的。为了更好的表述封装设计过程,本文描述了CH340G和MAX232芯片封装创建(SOP-16),并将原理图的元器件关联引脚封装。
硬件开发笔记(十): 硬件开发基本流程,制作一个USB转RS232的模块(九):创建CH340G/MAX232封装库sop-16并关联原理图元器件