当前位置: 首页 > 知识库问答 >
问题:

动态分区修剪不清楚

吕翰飞
2023-03-14

我试图理解spark 3中的新特性:动态分区修剪。

看看这个测试:

https://github.com/apache/spark/blob/master/sql/core/src/test/scala/org/apache/spark/sql/DynamicPartitionPruningSuite.scala#L257

我不明白为什么它是动态的并且要经典的修剪?

谢谢

共有2个答案

汝臻
2023-03-14

这正好显示了传统数据库优化器的进步有多大。

如果您有一个表/存储,其中在where/filter上提供了文字,则分区修剪与Spark一起工作,它知道在“解析”时过滤分区。

对于动态分区修剪,当优化器无法在“解析时”识别它必须消除的实际分区时也会发生这种情况。即在“运行时”,它可以决定要消除哪个分区。

例如星型模式连接,维度过滤掉所需的数据(例如月份或月份),事实表基于实际过滤,即按月份分区。

裴畅
2023-03-14

随着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很可能会将连接作为广播散列连接来执行。每当我们有两个散列连接的表时,就会发生很多事情-

  1. 首先,Spark 从维度表中生成一个哈希表,我们称之为构建关系。
  2. 执行此生成关系后,它会将该端的结果插入到广播变量中。Spark 将该变量分布到参与计算的所有工作线程中。
  3. 通过这样做,我们能够执行连接而无需随机播放。
  4. 然后,spark 将开始使用来自每个工作线程节点上的事实数据表的行来探测该哈希表。

这两个阶段之间显然有一个天然的障碍。所以首先我们计算连接的广播端。我们分发它,然后我们才开始探测和执行实际的连接。这非常有趣,我们希望能够利用这一点进行优化。因为这正是我们在子查询的逻辑规划级别上所模仿的。

下面是我们实际要做的。我们正在截取构建端的结果——广播结果。我们将直接获取它们,并将它们作为动态过滤器插入事实表顶部的扫描仪中。因此,这实际上是一个非常有效和优化的动态分区修剪版本。

总而言之,在Apache smks 3.0中,实现了一种称为动态分区修剪的新优化,它既适用于:

  1. 逻辑规划级别,用于查找维度筛选器并跨连接传播到扫描的另一侧。
  2. 物理级别,以此筛选器仅在维度侧执行一次的方式将其连接在一起。
  3. 然后,过滤器的结果直接在表的扫描中重复使用。通过这种双重方法,我们可以在 Spark 中的许多查询中实现显著的加速。

希望这个回答有帮助!

 类似资料:
  • 主要内容:动态分区比固定分区的优势,动态分区的缺点,复杂的内存分配动态分区试图克服由固定分区造成的问题。 在这种技术中,分区大小最初并未声明。 它在进程加载时声明。 第一个分区是为操作系统保留的。 剩余空间分成几部分。 每个分区的大小将等于进程的大小。 分区大小根据进程的需要而变化,以避免内部碎片。 动态分区比固定分区的优势 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)和插件版本 这两种情况下的作业