我试图理解spark 3中的新特性:动态分区修剪。
看看这个测试:
https://github.com/apache/spark/blob/master/sql/core/src/test/scala/org/apache/spark/sql/DynamicPartitionPruningSuite.scala#L257
我不明白为什么它是动态的并且要经典的修剪?
谢谢
这正好显示了传统数据库优化器的进步有多大。
如果您有一个表/存储,其中在where/filter上提供了文字,则分区修剪与Spark一起工作,它知道在“解析”时过滤分区。
对于动态分区修剪,当优化器无法在“解析时”识别它必须消除的实际分区时也会发生这种情况。即在“运行时”,它可以决定要消除哪个分区。
例如星型模式连接,维度过滤掉所需的数据(例如月份或月份),事实表基于实际过滤,即按月份分区。
随着Spark 3.0的发布,实施了重大改进,使Spark能够更快地执行,并且随之而来的是许多新功能。其中,动态分区修剪就是其中之一。在深入研究动态分区修剪中的新功能之前,让我们了解什么是分区修剪。
在标准数据库中,修剪意味着优化器将避免读取不能包含您正在寻找的数据的文件。举个例子,
select * from Students where subject = ‘English’;
在这个简单的查询中,我们试图匹配和识别学生表中属于学科英语的记录。这转化为一种简单的形式,即扫描之上的过滤器,这意味着首先扫描整个数据,然后根据条件过滤掉。
现在,大多数查询优化器试图从扫描的顶部向下推过滤器,尽可能靠近数据源,以便能够避免扫描整个数据集。
在分区修剪技术中,它遵循过滤器下推方法,数据集被分区。因为在这种情况下,如果您的查询在分区列上有一个过滤器,您实际上可以跳过完整的分区文件集。
Spark中的分区修剪是一种性能优化,它限制了Spark在查询时读取的文件和分区的数量。在对数据进行分区后,符合某些分区筛选条件的查询通过允许Spark仅读取目录和文件的子集来提高性能。当存在分区筛选器时,催化剂优化器会向下推送分区筛选器。扫描仅读取与分区筛选器匹配的目录,从而减少磁盘I/O。
然而,实际上,数据工程师不只是在他们的查询中执行单个查询或单个过滤器,常见的情况是他们实际上有维度表,他们需要与较大的事实数据表联接的小表。因此,在这种情况下,我们不能再应用静态分区修剪,因为筛选器位于联接的一侧,而更具吸引力和修剪吸引力的表位于联接的另一侧。所以我们现在有一个问题。
select * from Students join DailyRoutine
where DailyRoutine.subject = ‘English’;
有些人可能会建议我们可以事先将维度表与事实表连接起来。这样,我们仍然可以对单个表触发静态修剪。然后他们可以在单独的查询中执行过滤器,如下所示。
这种方法有明显的缺点,因为首先我们必须执行这个相当昂贵的连接。我们正在复制数据,因为我们必须生成另一个中间表。这张桌子可以很宽,因为我们把一堆较小的桌子和一个大桌子连接在一起。它不仅很宽,而且在更新维度表时实际上非常难以管理。因此,每当我们进行更改时,我们实际上必须重新触发整个管道。
在这篇博客中,我们将学习一种完全不同的方法,我们将使用动态修剪进行过滤。这种优化的基本目标是能够从维度表中获取过滤结果。然后直接使用它们来限制我们将从事实表中获得的数据。
在 Spark SQL 中,用户通常使用自己喜欢的编程语言从自己喜欢的 API 提交查询,因此我们有数据帧和数据集。Spark 接受此查询并将其转换为可理解的形式,我们称之为查询的逻辑计划。在此阶段,spark 通过应用一组基于规则的转换(如列修剪、常量折叠、过滤器下推)来优化逻辑计划。只有稍后,它才会进入查询的实际物理规划。在物理计划阶段,spark 会生成一个可执行的计划。此计划将计算分布在许多计算机的群集中。在这里,我将解释如何在逻辑规划级别实现动态分区修剪。然后,我们将研究如何在物理规划期间进一步优化它。
让我们从逻辑规划层面的优化机会开始。让我们考虑一个跨多个文件分区的数据集。且每个分区将因特定颜色而不同。另一方面,我们将有一个较小的表,它是一个不一定分区的维度表。在这些数据集之上,我们还有典型的扫描操作符。每当我们过滤维度表时,考虑这样一个例子,其中只有对应于连接另一侧的两个分区的行才是真正相关的。所以当我们完成最后的连接操作时,只有这两个分区会被连接保留。
因此,我们实际上不需要扫描整个事实表,因为我们只对维度表产生的两个过滤分区感兴趣。为了避免这种情况,一个简单的方法是将维度表中的过滤器合并到子查询中。然后在事实表扫描下运行子查询。
通过这种方式,我们可以在计划连接的事实方面时弄清楚这一点。我们能够确定此连接需要哪些数据。这是一种简单的方法。
但是,它实际上可能很贵。我们需要消除这种重复的子查询,并找出一种更有效的方法。为了做到这一点,我们将看看spark如何在物理规划期间执行连接,以及spark如何在这个物理规划阶段转换查询。
如果维度表很小,那么spark很可能会将连接作为广播散列连接来执行。每当我们有两个散列连接的表时,就会发生很多事情-
这两个阶段之间显然有一个天然的障碍。所以首先我们计算连接的广播端。我们分发它,然后我们才开始探测和执行实际的连接。这非常有趣,我们希望能够利用这一点进行优化。因为这正是我们在子查询的逻辑规划级别上所模仿的。
下面是我们实际要做的。我们正在截取构建端的结果——广播结果。我们将直接获取它们,并将它们作为动态过滤器插入事实表顶部的扫描仪中。因此,这实际上是一个非常有效和优化的动态分区修剪版本。
总而言之,在Apache smks 3.0中,实现了一种称为动态分区修剪的新优化,它既适用于:
希望这个回答有帮助!
主要内容:动态分区比固定分区的优势,动态分区的缺点,复杂的内存分配动态分区试图克服由固定分区造成的问题。 在这种技术中,分区大小最初并未声明。 它在进程加载时声明。 第一个分区是为操作系统保留的。 剩余空间分成几部分。 每个分区的大小将等于进程的大小。 分区大小根据进程的需要而变化,以避免内部碎片。 动态分区比固定分区的优势 1. 没有内部碎片 考虑到动态分区中的分区是根据进程的需要创建的,很明显,不会有任何内部碎片,因为分区中不会有任何未使用的剩余空间。 2.
跟踪自由或填充分区的更好和最流行的方法是使用链表。 在这种方法中,操作系统维护一个链表,每个节点代表每个分区。 每个节点都有三个字段。 节点的第一个字段存储一个标志位,该标志位显示该分区是一个洞还是某个进程在里面。 第二个字段存储分区的起始索引。 第三个字段存储分区的结束索引。 如果某个分区在某个时间点被释放,那么该分区将与其相邻的空闲分区合并,而不会做任何额外的工作。 在使用这种方法时需要注意一
问题内容: 我正在研究一个Java代码,它基于INSERT_DATETIME字段(时间戳)每15分钟从oracle表中上传数据。我需要根据15分钟的间隔对表进行分区。有没有办法动态地做到这一点(分区)。我在oracle SQL开发人员中使用oracle11g。 我创建的表之一的示例,我想添加一个分区: 我对SQL不熟悉,因为上面的代码只是从我创建的表中生成的。任何帮助表示赞赏。谢谢你 问题答案:
insert overwrite from select语句中的配置单元动态分区没有加载动态分区的数据,而是提供了数据配置单元默认分区。 如果我说显示分区表2; 它只给出一个分区细节,即配置单元默认分区 我有一个没有任何分区的暂存表,它从序列文件中读取数据。 如果不存在,则创建外部表table1(DS字符串、col1字符串、col2字符串、col3字符串) 行格式分隔字段,以存储为SEQUENCE
欢迎阅读另一个 Matplotlib 教程! 在本教程中,我们将清除图表,然后再做一些自定义。 我们当前的代码是: import matplotlib.pyplot as plt import matplotlib.dates as mdates import matplotlib.ticker as mticker from matplotlib.finance import candlesti
我们目前在一个Jenkins实例(生产性实例)中处理多分支测试作业的bitket分支源插件遇到了一些问题: 在Jenkins中,任何与已删除分支相关的作业都不会被删除。is显示为禁用。 检查我发现以下条目: 我们有另一个实例(测试实例),其中一切都按预期工作-分支立即被删除,例如在日志中看到以下内容: 对于这两种情况,我们使用相同的Jenkins版本(2.212.2)和插件版本 这两种情况下的作业