上一篇文章中我们主要讨论了Replace Operators、Aggregate和Operator Optimisation的一部分规则,这篇文章将继续讨论剩下的优化器批次规则,首先继续对Operator Optimization批次规则进行讲解。

Batch – Operator Optimization

CollapseRepartition

CollapseRepartition规则结合了相邻的repartition运算符。有过spark开发经验的都知道,repartition函数和coalesce函数均可以用来改变数据集的分区数量。repartition函数可以用来增加或减少分区,从而达到shuffle的目的,而coalesce函数只能用来减少分区的数量,而这些分区不能实现shuffle。

当一个非shuffle Repartition(coalesce)操作符有一个shuffle Repartition操作符的子级操作符时,如果父集操作符的numPartitions更大,则返回子级操作符:

spark 中的repartition可以设置多大 spark coalesce repartition_sql

spark 中的repartition可以设置多大 spark coalesce repartition_spark_02

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_03

如果shuffle Repartition的numPartition更大,则保持两个Repartition操作符不变:

spark 中的repartition可以设置多大 spark coalesce repartition_sql_04

spark 中的repartition可以设置多大 spark coalesce repartition_spark_05

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_06

当一个RepartitionByExpression操作符有一个Repartition或RepartitionByExpression的子级操作符时,移除该子级操作符。

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_07

CollapseProject

collapseProject规则结合了两个投影操作符。如下面的例子所示,两个投影操作符被合并为一个:

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_08

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_09

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_10

Combine Operators

考虑到以下规则的工作方式类似,我将一并解释它们。

  • CombineFilters
  • CombineLimits
  • CombineUnions

那些组合运算符规则通过合并运算符的条件将两个相邻的运算符合并为一个。

CombineFilters规则通过使用AND逻辑合并两个过滤器操作符的过滤条件,将两个相邻的过滤器合并为一个。

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_11

CombineLimits规则合并了两个相邻的Limit运算符,并使用较小的limit值。

spark 中的repartition可以设置多大 spark coalesce repartition_sql_12

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_13

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_14

CombineUnions规则合并了所有的Union操作符。

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_15

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_16

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_17

Constant Evaluation

下面的规则主要用于处理常数,所以我把它们放在一起:

  • NullPropagation
  • ConstantPropagation
  • OptimizeIn
  • ConstantFolding
  • ReorderAssociativeOperator
  • ReplaceNullWithFalseInPredicate
  • CombineConcats

NullPropagation规则根据数据类型,用相等的值来等价替换Null值。

spark 中的repartition可以设置多大 spark coalesce repartition_spark_18

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_19

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_20

ConstantPropagation规则用可以在联合表达式中等价的值来替换一个属性。以下面的查询为例,过滤条件第二部分的id属性,order_id = 100 + id,可以用第一部分的id值来替代。

spark 中的repartition可以设置多大 spark coalesce repartition_spark_21

spark 中的repartition可以设置多大 spark coalesce repartition_sql_22

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_23

OptimizeIn规则用于优化IN谓词。当IN值列表中存在重复值时,重复的部分将被删除。

spark 中的repartition可以设置多大 spark coalesce repartition_spark_24

spark 中的repartition可以设置多大 spark coalesce repartition_sql_25

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_26

此外,如果IN值列表的大小大于预定的阈值,IN运算符将被替换为INSET运算符,后者的速度会快很多。

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_27

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_28

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_29

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_30

ConstantFolding规则对表达式进行评估,并将其替换为等价的Literal值。

spark 中的repartition可以设置多大 spark coalesce repartition_sql_31

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_32

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_33

RecorderAssociativeOperator规则首先对关联的整型运算符进行重新排序,然后将所有常数折叠(fold)成一个。

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_34

spark 中的repartition可以设置多大 spark coalesce repartition_sql_35

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_36

nullvalue(空值)在一个谓词中被评估为false。ReplaceNullWithFalseInPredicate规则将空值替换为false。

spark 中的repartition可以设置多大 spark coalesce repartition_spark_37

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_38

spark 中的repartition可以设置多大 spark coalesce repartition_spark_39

CombineConcats规则结合了嵌套的concat表达式。

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_40

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_41

Operator Simplication

The following rules are mainly used for simplifying operators:

以下规则主要用于简化运算符。

  • LikeSimplification
  • BooleanSimplification
  • SimplifyConditionals
  • SimplifyBinaryComparison
  • PruneFilters
  • SimplifyCasts
  • SimplifyCaseConversionExpressions
  • RewriteCorrelatedScalarSubquery
  • EliminateSerialization
  • RemoveRedundantAliases
  • SimplifyExtractValueOps

LIKE表达式可以用来在谓词中匹配一个完整的正则表达式的字符串。当要匹配的模式不需要完整的正则表达式时,例如'%abc'(用于startsWith条件)或'abc%'(用于endsWith条件),LikeSimplification规则可以用更快的StartsWith或EndsWith表达式替换Like表达式。

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_42

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_43

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_44

BooleanSimplification规则简化了谓词中的布尔表达式。当一个谓词由多个布尔表达式部分组成时,如果一个表达式部分可以在不评估其他部分的情况下被确定,该谓词可以被简化。

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_45

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_46

spark 中的repartition可以设置多大 spark coalesce repartition_spark_47

当一个过滤条件由常数组成并且可以在优化阶段确定时,SimplifyConditionals会移除条件并直接返回结果(由条件决定)。

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_48

spark 中的repartition可以设置多大 spark coalesce repartition_spark_49

spark 中的repartition可以设置多大 spark coalesce repartition_sql_50

当二元比较的结果可以在优化阶段确定时,SimplifyBinaryComparison规则将二元比较表达式替换为语义上相等的真或假表达式

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_51

spark 中的repartition可以设置多大 spark coalesce repartition_sql_52

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_53

The PruneFiltersrule removes the filters that can be evaluated trivially.

PruneFilters规则删除了可以被琐碎地评估的过滤器。

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_54

spark 中的repartition可以设置多大 spark coalesce repartition_sql_55

spark 中的repartition可以设置多大 spark coalesce repartition_spark_56

当要转换的值的数据类型与预期的数据类型相同时,SimplifyCasts规则将不必要的转换表达式删除。

spark 中的repartition可以设置多大 spark coalesce repartition_spark_57

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_58

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_59

当一些表达式可以在优化阶段被评估和解决时,SimplifyCaseConversionExpression规则会移除大小写转换表达式。

spark 中的repartition可以设置多大 spark coalesce repartition_sql_60

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_61

spark 中的repartition可以设置多大 spark coalesce repartition_sql_62

RewriteCorrelatedScalarSubquery规则将相关的ScalarSubquery表达式重写为LEFT OUTER连接。

spark 中的repartition可以设置多大 spark coalesce repartition_sql_63

spark 中的repartition可以设置多大 spark coalesce repartition_sql_64

spark 中的repartition可以设置多大 spark coalesce repartition_spark_65

优化后的查询可以用下面的方式表示:

spark 中的repartition可以设置多大 spark coalesce repartition_sql_66

EliminateSerialization规则消除了不必要的序列化或反序列化操作。例如,在下面的查询中,连续的map操作会有一个SerializeFromObject操作,紧接着一个DesericalizeToObject操作。由于在第一个map操作和第二个map操作之间的节点不需要进行数据交换,所以中间的序列化/反序列化操作是不必要的,可以被删除。

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_67

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_68

spark 中的repartition可以设置多大 spark coalesce repartition_spark_69

当一个别名不改变列的名称或元数据时,这个别名是多余的,对查询没有用处。removeRedundantAliases规则会从逻辑计划中删除多余的别名。

spark 中的repartition可以设置多大 spark coalesce repartition_sql_70

spark 中的repartition可以设置多大 spark coalesce repartition_sql_71

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_72

当查询所需的值可以直接提取时,SimplifyExtractValueOps规则会删除不必要的数据结构创建。

Array数据结构的例子:

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_73

spark 中的repartition可以设置多大 spark coalesce repartition_sql_74

Map数据结构的例子:

spark 中的repartition可以设置多大 spark coalesce repartition_spark_75

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_76

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_77

Named_Struct数据结构的例子:

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_78

spark 中的repartition可以设置多大 spark coalesce repartition_spark_79

Batch – Early Filter and Projection Push-Down

这个批次是一个占位符,用于将过滤器和投影推送到扫描节点的规则。

Batch – Join Reorder

这个批次包括CostBasedJoinReorder规则,它是一个基于成本的优化器规则(cost-based Optimizer rule),用于根据连接中涉及的关系的统计数字找到最有效的连接顺序。

Spark SQL中成本模型背后的基本思想是计算Spark Planner生成的所有候选物理计划的成本,然后选择成本最低的一个。然而,在Spark 3.0.0之前,成本模型尚未实现。相反,在逻辑计划优化阶段应用CostBasedJoinReorderrule。要启用此规则,请使用spark.sql.cbo.enabledflagspark.sql.cbo.joinReorder.enabledflag需要设置为true。

CostBasedJoinReorder规则收集join操作中涉及的关系的统计数据,计算所有有效连接组合的成本,并使用预定义的成本公式找到最佳连接组合。

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_80

Batch – Eliminate Sorts

这个批次包括EliminateSorts规则,它删除了必要的Sort运算符。

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_81

spark 中的repartition可以设置多大 spark coalesce repartition_sql_82

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_83

Batch – Decimal Optimizations

这个批次是用来优化小数计算的。在Spark 3.0.0中,本批中包括一条规则,DecimalAggregates。DecimalAggregates规则,如果可能的话,在内部将小数转换为未缩放的Long值。使用未缩放(unscaled)的十进制的Long值预计会加速聚合计算。

spark 中的repartition可以设置多大 spark coalesce repartition_操作符_84

spark 中的repartition可以设置多大 spark coalesce repartition_运算符_85

spark 中的repartition可以设置多大 spark coalesce repartition_大数据_86

Batch – Object Expressions Optimization

本批包括与数据集API的对象操作有关的优化器规则,包括。

  • EliminateMapObjects--如果输入和输出的类型是原始类型,且不可置空,没有指定数据项的自定义集合类表示,则消除MapObjects操作。
  • CombineTypedFilters - 将两个相邻的TypedFilters合并为一个。
  • ObjectSerializerPruning - 删减不必要的对象序列化器
  • ReassignLambdaVariableID - 为LambdaVriables重新分配每个查询的唯一ID,这样可以更频繁地访问codegen缓存。

Batch – LocalRelation

LocalRelation批次将被执行两次,第一次执行是在执行主要优化器规则之前,第二次执行是在之后。第一批执行已经在之前的博文:基于规则的Spark SQL Catalyst优化器(一)中解释过了,主要是简化逻辑计划以避免潜在的重度优化器规则。这是第二批执行,它整理了由空的局部关系组成的逻辑计划。空的局部关系是由"Operator Optimization"批次中的PruneFilters规则产生的。因此,这个批次的执行时间在"Operator Optimization"批次之后。

Batch – Check Cartesian Products

这个批处理包括CheckCartesianProducts规则,它检查一个join操作是否是一个笛卡尔的乘积。当CROSS_JOIN_ENABLED标志被设置为false时,如果join是一个笛卡尔乘积,则抛出一个错误。

Batch – RewriteSubquery

该批次包括以下优化器规则,这些规则也包括在之前执行的"Operator Optimization"批次中。

  • RewritePredicateSubquery
  • ColumnPruning
  • CollapseProject
  • RemoveNoopOperators

这些规则的另一次运行可以优化"Operator Optimization"批量执行后产生的operators 。

Batch – NormalizeFloatingNumbers

该批处理包括normalizeefloatingnumbers规则,该规则处理特殊的浮点数(例如NaN和0.0/-0.0)。在这种情况下,不同的NaNs需要被视为相同,并且“0.0”和“-0.0”需要也被视为相同,包括值比较、聚合分组键、连接键和窗口分区键。