文章目录

  • 1.Spark执行流程概述
  • SparkSQL的使用一般步骤:
  • Spark对SQL语句的转换
  • 2.Catalyst
  • 基础的SQL优化器理论:
  • Catalyst工作流程
  • 在spark环境中查看SparkSQL执行计划


1.Spark执行流程概述

SparkSQL的使用一般步骤:

  1. 创建SparkSession类:
val session = SparkSession.builder()
  .appName("SparkSQLTest")
  .master("local[*]")
  .getOrCreate()
  1. 创建数据表并读取数据:
session.read.textFile/json..
session.sparkContext.textFile/...
  1. 通过sql或者DataFrame的api进行数据分析
session.sql(...)

Spark对SQL语句的转换

SparkSQL中,从SQL语句到Spark中执行RDD需要经过两个阶段:逻辑计划和物理计划,如图:

SQL作业Spark作业需要使用计算资源吗 spark sql的工作流程_子树

  • 逻辑计划阶段:逻辑计划阶段会将用户所写的 SQL 语句转换成树型数据结构(逻辑算子树), SQL 语句中蕴
    含的逻辑映射到逻辑算子树的不同节点。即逻辑计划阶段不会执行计划,仅作为中间阶段。
  • 逻辑算子树的生成过程经历 3 个子阶段:
  • 未解析的逻辑算子树( Unresolved Logica!Plan ,仅是数据结构,不包含任何数据信息等)
  • 解析后的逻辑算子树( Analyzed LogicalPlan ,节点中绑定各种信息
  • 优化后的逻辑算子树( Optimized LogicalPlan ,应用各种优化规则对一些低效的逻辑计划进行转换
  • 物理计划阶段:将上一步逻辑计划阶段生成的逻辑算子树进行进一步转换,生成物理算子树 。物理算子树的节点会直接生成 RDD 或对 RDD 进行 transformation 操作。每个物理计划节点中都实现了对 RDD 进行转换的 execute 方法
  • 物理计划阶段也包含 3 个子阶段 :
  • 根据逻辑算子树,生成物理算子树的列表 Iterator[PhysicalPlan] (同样的逻辑算子树可能对应多个物理算子树)
  • 从列表中按照一定的策略选取最优的物理算子树( SparkPlan
  • 对选取的物理算子树进行提交前的准备工作,例如,确保分区操作正确、物理算子树节点重用、执行代码生成等,得到“准备后”的物理算子树( Prepared SparkPlan
  • 经过逻辑和物理计划后,物理算子树生成的RDD执行action操作;
  • 从 SQL 语句的解析一直到提交之前,上述整个转换过程都在 Spark 集群的 Driver 端进行
  • SparkSession 类的 sql方法调用 SessionState 中的各种对象 ,包括上述不同阶段对应的 SparkSqlParser 类、 Analyzer 类、 Optimizer 类和 SparkPlanner 类等**(逻辑执行计划),最后封装成一个QueryExecution 对象**,可以很方便地将每一步生成的计划单独剥离出来分析。
    下图中物理算子树根节点是ProjectExec,每个物理节点中的 execute 函数都是执行调用接口,由根节点开始递归调用,从叶子节点开始执行
  • SQL作业Spark作业需要使用计算资源吗 spark sql的工作流程_大数据_02

2.Catalyst

Spark SQL 内部实现上述流程中平台无关部分的基础框架(优化器系统)称为 Catalyst

基础的SQL优化器理论:

SQL优化器核心执行策略主要分为两个大的方向:基于规则优化(RBO)以及基于代价优化(CBO)

  • 基于规则优化:是一种经验式、启发式地优化思路,更多地依靠前辈总结出来的优化规则,简单易行且能够覆盖到大部分优化逻辑,但是对于核心优化算子Join却显得有点力不从心。
  • 举个简单的例子,两个表执行Join到底应该使用BroadcastHashJoin还是SortMergeJoin?特别是在雪花模型或者星形模型,多表Join怎么执行?当前SparkSQL的方式是通过手工设定参数来确定,如果一个表的数据量小于这个值就使用BroadcastHashJoin,但是这种方案显得很不优雅,很不灵活。
  • 基于代价优化:就是为了解决上类问题,基于代价优化会针对每个Join评估当前两张表使用每种Join策略的代价,根据代价估算确定一种代价最小的方案,从多个可能的语法树中选择一条代价最小的语法树来执行。

SparkSQL采用的是基于规则优化。Catalyst的整个工作流程,包括Parser阶段、Analyzer阶段、Optimize阶段以及Physical Planning阶段。即下图红框中的内容:

SQL作业Spark作业需要使用计算资源吗 spark sql的工作流程_子树_03

  • SQL优化器的基础数据结构:Tree和Rule
  • **Tree:**Sql语法树就是SQL语句通过编译器之后会被解析成一棵树状结构。这棵树会包含很多节点对象,每个节点都拥有特定的数据类型,同时会有0个或多个孩子节点(节点对象在代码中定义为TreeNode对象)。如下图
  • Rule:任何一个SQL优化器中,通常会定义大量的Rule(后面会讲到),SQL优化器会遍历语法树中每个节点,针对遍历到的节点模式匹配所有给定规则(Rule),如果有匹配成功的,就进行相应转换,如果所有规则都匹配失败,就继续遍历下一个节点。如下图

Catalyst工作流程

  • 工作原理:SQL语句首先通过Parser模块被解析为语法树,此棵树称为Unresolved Logical Plan;Unresolved Logical Plan通过Analyzer模块借助于数据元数据解析为Logical Plan;此时再通过各种基于规则的优化策略进行深入优化,得到Optimized Logical Plan;优化后的逻辑执行计划依然是逻辑的,并不能被Spark系统理解,此时需要将此逻辑执行计划转换为Physical Plan
  • 基础概念
  • Parser:Parser简单来说是将SQL字符串切分成一个一个Token,再根据一定语义规则解析为一棵语法树。Parser模块目前基本都使用第三方类库ANTLR进行实现,比如Hive、 Presto、SparkSQL等。
  • Analyzer:通过解析后的逻辑执行计划基本有了骨架,但是系统不知道语句中表的字段函数等信息,此时需要基本的元数据信息来表达这些词素,最重要的元数据信息主要包括两部分:表的Scheme和基本函数信息,表的scheme主要包括表的基本定义(列名、数据类型)、表的数据格式(Json、Text)、表的物理位置等,基本函数信息主要指类信息。Analyzer会再次遍历整个语法树,对树上的每个节点进行数据类型绑定以及函数绑定
    Sparksql中的Analyzer类中定义了基本解析规则,如下图:

SQL作业Spark作业需要使用计算资源吗 spark sql的工作流程_大数据_04


- **Optimizer:**优化器是整个Catalyst的核心,上文提到优化器分为基于规则优化和基于代价优化两种,当前SparkSQL 主要轴承基于规则优化,基于规则的优化策略实际上就是对语法树进行一次遍历,模式匹配能够满足特定规则的节点,再进行相应的等价转换。因此,基于规则优化说到底就是一棵树等价地转换为另一棵树。SQL中经典的优化规则有很多,例如:谓词下推(Predicate Pushdown)、常量累加(Constant Folding)和列值裁剪(Column Pruning)。

  • 经过Parser,Analyzer和Optimizer,逻辑执行计划已经构建完成,然而都还只是抽象的,只是逻辑上可笑,此时就需要将逻辑执行计划转换成物理执行计划,将逻辑上可行的执行计划变为Spark可以真正执行的计划。物理执行计划实际上就是在这些具体实现中挑选一个耗时最小的算法实现。

在spark环境中查看SparkSQL执行计划

  1. 在命令行中通过:session.sql(’…’).queryExecution/explain方法,分别查看逻辑和物理执行计划
  2. 使用Spark WEBUI进行查看