Spark 开源新特性:Catalyst 优化流程裁剪
摘要:为了解决过多依赖 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 优化流程裁剪相关推荐
- C# 10 新特性 —— Lambda 优化
C# 10 新特性 -- Lambda 优化 Intro C# 10 对于 Lambda 做了很多的优化,我们可以在 C# 中更加方便地使用委托和 Lambda 了,下面就来看一些示例 Lambda ...
- Tengine开源新特性:如何让HTTPS处理能力轻松翻倍?
阿里妹导读:Tengine,轻量级Web服务器,基于Nginx进行开发,针对大访问量网站的需求,新增了很多高级功能和特性.比如,Tengine兼容Nginx的所有配置,并且增加了独立进程框架.页面优化 ...
- 【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. ...
- 新特性解读 | MySQL 8.0 对 limit 的优化
作者:杨奇龙 网名"北在南方",资深 DBA,主要负责数据库架构设计和运维平台开发工作,擅长数据库性能调优.故障诊断. 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不 ...
- Spark SQL架构工作原理及流程解析
Spark SQL架构工作原理及流程解析,spark sql从shark发展而来,Shark为了实现Hive兼容,在HQL方面重用了Hive中HQL的解析.逻辑执行计划翻译.执行计划优化等逻辑. Sp ...
- jQuery 1.4 版本的十五个新特性-转载
jQuery 1.4 最近发布了. 超乎大家的预期,这次并非简单的修修补补,1.4 包含了很多新特性.功能增强和性能提升!本文即向您介绍这些可能对你十分有用的新特性和优化增强. 你可以立刻下载jQue ...
- jQuery1.4的15个新特性实例精讲
为什么80%的码农都做不了架构师?>>> jQuery 1.4 的发布超乎大家的预期,这次并非简单的修修补补,1.4 包含了很多新特性.功能增强和性能提升!本文即向您介绍这些可 ...
- 技术前沿资讯-Apache Flink 1.14 新特性介绍
一.简介 1.14 新版本原本规划有 35 个比较重要的新特性以及优化工作,目前已经有 26 个工作完成:5 个任务不确定是否能准时完成:另外 4 个特性由于时间或者本身设计上的原因,会放到后续版本完 ...
- Flink 1.14 新特性预览
简介: 一文了解 Flink 1.14 版本新特性及最新进展 本文由社区志愿者陈政羽整理,内容源自阿里巴巴技术专家宋辛童 (五藏) 在 8 月 7 日线上 Flink Meetup 分享的<Fl ...
最新文章
- css3循环播放一组动画,CSS3 无穷循环的动画演示
- 什么是初效过滤器_聊聊中效过滤器的哪些事?
- linux系统的学习经验首篇
- ML之RF:利用Pipeline(客户年龄/职业/婚姻/教育/违约/余额/住房等)预测客户是否购买该银行的产品二分类(预测、推理)
- GitHub进一步了解
- day9 java的静态代码块和代码执行顺序
- python_对象的基本组成和内存示意图---python工作笔记016
- python能和java一起编程吗_C如何能和Python一起编程,那么它们已经无敌了!Java靠边站!...
- 四合一小说漫画听书视频网站源码 带采集
- 2010年06期《程序员》配套源码及相关链接
- 雷达的工作原理示意图_雷达基本理论与基本原理
- react源码分析:babel如何解析jsx
- mysql查询多选项商品查询_MYSQL中的多类型查询及高级查询操作
- 汇编笔记-在屏幕中间分别显示绿色,绿底红色,白底蓝色的字符串“welcome to masm!”
- vue直传图片到阿里云OSS(单张直接上传)
- 大疆云台和华为P30_全面分析曝光大疆云台3和mobile有没有区别?哪个好?优缺点内幕透露...
- 网易2017春招 魔力手环 矩阵快速幂
- Excel常用工具---在线版V1.5使用说明
- [转载]2017 中国电信(美洲)公司CTExcel US电话卡使用攻略_拔剑-浆糊的传说_新浪博客
- 美团外卖广告智能算力的探索与实践
热门文章
- CSS3单词及属性大全
- JavaScript 使用对象及ES6中的class
- robot motion planning介绍
- c和JAVA的安全编码_C、C++ 和 Java安全编码实践提示与技巧
- pcie16x能插1x的卡嘛?_5G手机插4G卡,在没有5G信号的地方,跟4G手机的网速一样吗?...
- Ubuntu 出现 Invalid operation update 或 Invalid operation upgrade的解决办法
- java设置jdk环境变量
- HTML中文网页乱码问题
- 软件测试(一)-黑盒测试 随机测试技巧
- 常用freemarker使用文档