这篇文章把spark3.2目前用到的所有的逻辑执行计划的优化规则整理了一遍,有需要的点赞收藏,后面用到的时候,就可以随时看啦~~
相关文章:sparksql源码系列 | 生成resolved logical plan的解析规则整理,这一篇是spark3.2最全的logical plan 解析规则整理
整体上分为标准的优化规则和特殊的优化规则,这是为了实现上的扩展性。
-
标准优化规则
-
过滤推断前的算子优化-operatorOptimizationRuleSet
-
过滤推断-Infer Filters
-
过滤推断后的算子优化-operatorOptimizationRuleSet
-
下推join的额外谓词-Push extra predicate through join
-
算子下推(Operator push down)-Project、Join、Limit、列剪裁
-
算子合并(Operator combine)-Repartition、Project、Window、Filter、Limit、Union
-
常量折叠和强度消减(Constant folding and strength reduction)-Repartition、Window、Null、常量、In、Filter、整数类型、Like、Boolean、if/case、二义性、no-op、struct、取值操作(struct/array/map)、csv/json、Concat
-
analysis 阶段的收尾规则-Finish Analysis,比如EliminateSubqueryAliases实际是在Analyzer里定义的
-
算子优化前-Union、Limit、数据库关系、子查询、算子的替代、聚合算子
-
算子优化-operatorOptimizationBatch
-
依赖统计数据的优化规则-Project、Filter、Join、Sort、Decimal、Aggregate、对象表达式、数据库关系、笛卡尔积、子查询、Float、Struct
-
-
其他特殊的优化规则-分区元数据、DPP(动态分区裁剪)、Filter、Python UDF以及用户自定义的优化规则
基于spark3.2 branch
rule【规则】 | batch【表示一组同类的规则】 | strategy【迭代策略】 | 注释 |
EliminateDistinct | Eliminate Distinct | Once | 删移除关于MAX和MIN的无效DISTINCT。在 RewriteDistinctAggregates 之前,应该先应用此规则。 |
EliminateResolvedHint | Finish Analysis | Once | 替换计划中的ResolvedHint算子。将HintInfo移动到关联的Join算子,否则,如果没有匹配的Join算子,就将其删除。HintInfo 是要应用于特定节点的提示属性 |
EliminateSubqueryAliases | Finish Analysis | Once | 消除子查询别名,对应逻辑算子树中的SubqueryAlias节点。一般来讲,Subqueries 仅用于提供查询的视角范围(Scope)信息,一旦 analysis 阶段结束, 该节点就可以被移除,该优化规则直接将SubqueryAlias替换为其子节点。 |
EliminateView | Finish Analysis | Once | 此规则将从计划中删除View算子。在analysis阶段结束之前,这个算子会一直受到尊重,因为我们希望看到AnalyzedLogicalPlan的哪一部分是从视图生成的。 |
InlineCTE | Finish Analysis | Once | 如果满足以下任一条件,则将CTE定义插入相应的引用中:1. CTE定义不包含任何非确定性表达式。如果此CTE定义引用了另一个具有非确定性表达式的CTE定义,则仍然可以内联当前CTE定义。2.在整个主查询和所有子查询中,CTE定义只被引用一次。此外,由于相关子查询的复杂性,无论上述条件如何,相关子查询中的所有CTE引用都是内联的。 |
ReplaceExpressions | Finish Analysis | Once | 查找所有无法执行的表达式,并用可计算的语义等价表达式替换/重写它们。目前,我们替换了两种表达式:1.RuntimeReplaceable表达式。2.无法执行的聚合表达式,如Every/Some/Any/CountIf 这主要用于提供与其他数据库的兼容性。很少有这样的例子:我们使用它来支持nvl,将其替换为coalesce。我们分别用Min和Max替换each和Any。 |
RewriteNonCorrelatedExists | Finish Analysis | Once | 为了使用ScalarSubquery需要重写非关联的exists子查询,比如:WHERE EXISTS (SELECT A FROM TABLE B WHERE COL1 > 10) 会被重写成 WHERE (SELECT 1 FROM (SELECT A FROM TABLE B WHERE COL1 > 10) LIMIT 1) IS NOT NULL 。ScalarSubquery是只返回一行和一列的子查询。这将在planning阶段转换为物理标量(scalar)子查询。 |
PullOutGroupingExpressions | Finish Analysis | Once | 此规则确保Aggregate节点在optimization阶段不包含复杂的分组表达式。复杂的分组表达式被拉到Aggregate下的Project节点,并在分组表达式和不带聚合函数的聚合表达式中引用。这些引用确保优化规则不会将聚合表达式更改为不再引用任何分组表达式的无效表达式,并简化节点上的表达式转换(只需转换表达式一次)。例如,在下面的查询中,Spark不应该将聚合表达式Not(IsNull(c))优化成IsNotNull(c),因为IsNull(c)是一个分组表达式:SELECT not(c IS NULL) FROM t GROUP BY c IS NULL |
ComputeCurrentTime | Finish Analysis | Once | 计算当前日期和时间,以确保在单个查询中返回相同的结果。 |
ReplaceCurrentLike | Finish Analysis | Once | 用当前数据库名称替换CurrentDatabase的表达式。用当前catalog名称替换CurrentCatalog的表达式。 |
SpecialDatetimeValues | Finish Analysis | Once | 如果输入字符串是可折叠的,则用其日期/时间戳值强制转换成特殊日期时间字符串。 |
RemoveNoopOperators | Union | Once | 从查询计划中删除不进行任何修改的 no-op 运算符。 |
CombineUnions | Union | Once | 将所有相邻的Union运算符合并成一个 |
RemoveNoopUnion | Union | Once | 简化 Union 的子节点,或者从查询计划中删除不修改查询的 no-op Union |
OptimizeLimitZero | OptimizeLimitZero | Once | 将GlobalLimit 0和LocalLimit 0节点(子树)替换为空的Local Relation,因为它们不返回任何数据行。 |
ConvertToLocalRelation | LocalRelation early | fixedPoint | 将LocalRelation上的本地操作(即不需要数据交换的操作)转换为另一个LocalRelation。 |
PropagateEmptyRelation | LocalRelation early | fixedPoint | 简化了空或非空关系的查询计划。当删除一个Union空关系子级时,PropagateEmptyRelation可以将属性(attribute)的可空性从可空更改为非空 |
UpdateAttributeNullability | LocalRelation early | fixedPoint | 通过使用其子输出属性(Attributes |