摘要:为了解决过多依赖 Hive 的问题, SparkSQL 使用了一个新的 SQL 优化器替代 Hive 中的优化器, 这个优化器就是 Catalyst。

本文分享自华为云社区《Spark 开源新特性:Catalyst 优化流程裁剪》,作者:hzjturbo 。

1. 问题背景

上图是典型的Spark Catalyst优化器的布局,一条由用户输入的SQL,到真实可调度执行的RDD DAG任务,需要经历以下五个阶段:

  • Parser: 将SQL解析成相应的抽象语法树(AST),spark也称为 Unresolved Logical Plan;
  • Analyzer: 通过查找Metadata的Catalog信息,将 Unresolved Logical Plan 变为 Resolved Logical Plan,这个过程会做表、列、数据类型等做校验;
  • Optimizer: 逻辑优化流程,通过一些优化规则对匹配上的Plan做转换,得到优化后的逻辑Plan
  • Planner:根据Optimized Logical Plan的统计信息等转换成相应的Physical Plan
  • Query Execution: 主要是执行前的一些preparations优化,比如AQE, Exchange Reuse, CodeGen stages合并等

上述的五个阶段中,除了Parser (由Antlr实现),其他的每个阶段都是由一个个规则(Rule)构成,总共大约有200+个,对于不同的规则,还可能需要跑多次,所以对于相对比较复杂的查询,可能得到一个executed Plan都需要耗费数秒。

Databricks内部基准测试表明,对于TPC-DS查询,每个查询平均调用树转换函数约280k次,这远远超出了必要的范围。因此,我们探索在每个树节点中嵌入BitSet,以传递自身及其子树的信息,并利用计划不变性来修剪不必要的遍历。通过原型实现验证:在TPC-DS基准测试中,我们看到优化的速度约为50%,分析的速度约为30%,整个查询编译的速度约为34%(包括Hive元存储RPC和文件列表)[1]。

2. 设计实现

2.1 Tree Pattern Bits and Rule Id Bits

  • Tree pattern bits

在TreeNode 增加nodePatterns属性,所有继承该类的节点可以通过复写该属性值来标识自己的属性。

/*** @return a sequence of tree pattern enums in a TreeNode T. It does not include propagated*         patterns in the subtree of T.*/
protected val nodePatterns: Seq[TreePattern] = Seq()

TreePattern 是一个枚举类型, 对于每个节点/表达式都可以为其设置一个TreePattern方便标识,具体可见 TreePatterns.scala 。

例如对于Join节点的nodePatterns:

override val nodePatterns : Seq[TreePattern] = {var patterns = Seq(JOIN)joinType match {case _: InnerLike => patterns = patterns :+ INNER_LIKE_JOINcase LeftOuter | FullOuter | RightOuter => patterns = patterns :+ OUTER_JOINcase LeftSemiOrAnti(_) => patterns = patterns :+ LEFT_SEMI_OR_ANTI_JOINcase NaturalJoin(_) | UsingJoin(_, _) => patterns = patterns :+ NATURAL_LIKE_JOINcase _ =>}patterns
}
  • Rule ID bits

将规则ID的缓存BitSet嵌入到每个树/表达式节点T中,这样我们就可以跟踪规则R对于根植于T的子树是有效还是无效。这样,如果R在T上被调用,并且已知R无效,如果R再次应用于T(例如,R位于定点规则批处理中),我们可以跳过它。这个想法最初被用于Cascades optimizer,以加快探索性规划。

Rule:

abstract class Rule[TreeType <: TreeNode[_]] extends SQLConfHelper with Logging {// The integer id of a rule, for pruning unnecessary tree traversals.protected lazy val ruleId = RuleIdCollection.getRuleId(this.ruleName)

TreeNode:

/*** A BitSet of rule ids to record ineffective rules for this TreeNode and its subtree.* If a rule R (which does not read a varying, external state for each invocation) is* ineffective in one apply call for this TreeNode and its subtree, R will still be* ineffective for subsequent apply calls on this tree because query plan structures are* immutable.*/
private val ineffectiveRules: BitSet = new BitSet(RuleIdCollection.NumRules)

2.2 Changes to The Transform Function Family

改造后的transform 方法相比之前的多了两个判断,如下所示

def transformDownWithPruning(cond: TreePatternBits => Boolean, // 判断是否存在可优化的节点,由规则设计者所提供ruleId: RuleId = UnknownRuleId // 不会生效的规则ID,自动更新)(rule: PartialFunction[BaseType, BaseType]): BaseType = {// 如果上述两个条件存在一个不满足,直接跳过本次规则if (!cond.apply(this) || isRuleIneffective(ruleId)) {return this}// 执行rule的逻辑val afterRule = CurrentOrigin.withOrigin(origin) {rule.applyOrElse(this, identity[BaseType])}// Check if unchanged and then possibly return old copy to avoid gc churn.if (this fastEquals afterRule) {val rewritten_plan = mapChildren(_.transformDownWithPruning(cond, ruleId)(rule))// 如果没生效,把规则ID加入到不生效的BitSet里if (this eq rewritten_plan) {markRuleAsIneffective(ruleId)this} else {rewritten_plan}} else {// If the transform function replaces this node with a new one, carry over the tags.afterRule.copyTagsFrom(this)afterRule.mapChildren(_.transformDownWithPruning(cond, ruleId)(rule))}
}

2.3 Changes to An Individual Rule

规则的例子:

object OptimizeIn extends Rule[LogicalPlan] with SQLConfHelper {def apply(plan: LogicalPlan): LogicalPlan = plan transform ({case q: LogicalPlan => q transformExpressionsDown ({case In(v, list) if list.isEmpty => ...case expr @ In(v, list) if expr.inSetConvertible => ...}, _.containsPattern(IN), ruleId) // 必须包含IN}, _.containsPattern(IN), ruleId) // 必须包含IN
}

3. 测试结果

在Delta中使用TPC-DS SF10对TPC-DS查询编译时间进行了基准测试。结果如下:

  • 图1显示了查询编译速度;
  • 表1显示了几个关键树遍历函数的调用计数和CPU减少的细分。

我简单运行了开版本的TPCDSQuerySuite,该测试会把TPCDS的语句解析优化,并且检查下生成的代码(CodeGen),平均耗时的时间为三次运行得到的最优值, 得到的结果如下:

  • 合入PR前[2], 包含156个Tpcds查询,平均总耗时~56s
  • 最新Spark开源代码,包含150个Tpcds查询,平均总耗时~19s

之所以最新的Tpcds查询比合入PR前的条数少6条,是因为后续有个减少重复TPCDS的PR。总时长优化前是优化后的两倍多。

参考引用

[1]. [SPARK-34916] Tree Traversal Pruning for Catalyst Transform/Resolve Function Families. SISP

[2]. [SPARK-35544][SQL] Add tree pattern pruning to Analyzer rules.

[3]. Building a SIMD Supported Vectorized Native Engine for Spark SQL. link

点击关注,第一时间了解华为云新鲜技术~

Spark 开源新特性:Catalyst 优化流程裁剪相关推荐

  1. C# 10 新特性 —— Lambda 优化

    C# 10 新特性 -- Lambda 优化 Intro C# 10 对于 Lambda 做了很多的优化,我们可以在 C# 中更加方便地使用委托和 Lambda 了,下面就来看一些示例 Lambda ...

  2. Tengine开源新特性:如何让HTTPS处理能力轻松翻倍?

    阿里妹导读:Tengine,轻量级Web服务器,基于Nginx进行开发,针对大访问量网站的需求,新增了很多高级功能和特性.比如,Tengine兼容Nginx的所有配置,并且增加了独立进程框架.页面优化 ...

  3. 【Flink】Flink 1.13 Flink SQL 新特性 性能优化 时区 时间 纠正

    文章目录 1.概述 2.window TVF 2.2 GROUPING 2.3 window TopN 2.4 RollUP 2.5 优化 3.时间 3.1 时间函数纠正 3.2 时间类型的使用 3. ...

  4. 新特性解读 | MySQL 8.0 对 limit 的优化

    作者:杨奇龙 网名"北在南方",资深 DBA,主要负责数据库架构设计和运维平台开发工作,擅长数据库性能调优.故障诊断. 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不 ...

  5. Spark SQL架构工作原理及流程解析

    Spark SQL架构工作原理及流程解析,spark sql从shark发展而来,Shark为了实现Hive兼容,在HQL方面重用了Hive中HQL的解析.逻辑执行计划翻译.执行计划优化等逻辑. Sp ...

  6. jQuery 1.4 版本的十五个新特性-转载

    jQuery 1.4 最近发布了. 超乎大家的预期,这次并非简单的修修补补,1.4 包含了很多新特性.功能增强和性能提升!本文即向您介绍这些可能对你十分有用的新特性和优化增强. 你可以立刻下载jQue ...

  7. jQuery1.4的15个新特性实例精讲

    为什么80%的码农都做不了架构师?>>>    jQuery 1.4 的发布超乎大家的预期,这次并非简单的修修补补,1.4 包含了很多新特性.功能增强和性能提升!本文即向您介绍这些可 ...

  8. 技术前沿资讯-Apache Flink 1.14 新特性介绍

    一.简介 1.14 新版本原本规划有 35 个比较重要的新特性以及优化工作,目前已经有 26 个工作完成:5 个任务不确定是否能准时完成:另外 4 个特性由于时间或者本身设计上的原因,会放到后续版本完 ...

  9. Flink 1.14 新特性预览

    简介: 一文了解 Flink 1.14 版本新特性及最新进展 本文由社区志愿者陈政羽整理,内容源自阿里巴巴技术专家宋辛童 (五藏) 在 8 月 7 日线上 Flink Meetup 分享的<Fl ...

最新文章

  1. css3循环播放一组动画,CSS3 无穷循环的动画演示
  2. 什么是初效过滤器_聊聊中效过滤器的哪些事?
  3. linux系统的学习经验首篇
  4. ML之RF:利用Pipeline(客户年龄/职业/婚姻/教育/违约/余额/住房等)预测客户是否购买该银行的产品二分类(预测、推理)
  5. GitHub进一步了解
  6. day9 java的静态代码块和代码执行顺序
  7. python_对象的基本组成和内存示意图---python工作笔记016
  8. python能和java一起编程吗_C如何能和Python一起编程,那么它们已经无敌了!Java靠边站!...
  9. 四合一小说漫画听书视频网站源码 带采集
  10. 2010年06期《程序员》配套源码及相关链接
  11. 雷达的工作原理示意图_雷达基本理论与基本原理
  12. react源码分析:babel如何解析jsx
  13. mysql查询多选项商品查询_MYSQL中的多类型查询及高级查询操作
  14. 汇编笔记-在屏幕中间分别显示绿色,绿底红色,白底蓝色的字符串“welcome to masm!”
  15. vue直传图片到阿里云OSS(单张直接上传)
  16. 大疆云台和华为P30_全面分析曝光大疆云台3和mobile有没有区别?哪个好?优缺点内幕透露...
  17. 网易2017春招 魔力手环 矩阵快速幂
  18. Excel常用工具---在线版V1.5使用说明
  19. [转载]2017 中国电信(美洲)公司CTExcel US电话卡使用攻略_拔剑-浆糊的传说_新浪博客
  20. 美团外卖广告智能算力的探索与实践

热门文章

  1. CSS3单词及属性大全
  2. JavaScript 使用对象及ES6中的class
  3. robot motion planning介绍
  4. c和JAVA的安全编码_C、C++ 和 Java安全编码实践提示与技巧
  5. pcie16x能插1x的卡嘛?_5G手机插4G卡,在没有5G信号的地方,跟4G手机的网速一样吗?...
  6. Ubuntu 出现 Invalid operation update 或 Invalid operation upgrade的解决办法
  7. java设置jdk环境变量
  8. HTML中文网页乱码问题
  9. 软件测试(一)-黑盒测试 随机测试技巧
  10. 常用freemarker使用文档