一条Sql的Spark之旅

一条Sql的Spark之旅背景 ​ SQL作为一门标准的、通用的、简单的DSL,在大数据分析中有着越来越重要的地位;Spark在批处理引擎领域当前也是处于绝对的地位,而Spark2.0中的SparkSQL也支持ANSI SQL

一条Sql的Spark之旅

背景

​ SQL作为一门标准的、通用的、简单的DSL,在大数据分析中有着越来越重要的地位;Spark在批处理引擎领域当前也是处于绝对的地位,而Spark2.0中的SparkSQL也支持ANSI-SQL 2003标准。因此SparkSQL在大数据分析中的地位不言而喻。
本文将通过分析一条SQL在Spark中的解析执行过程来梳理SparkSQL执行的一个流程。

案例分析

代码

val spark = SparkSession.builder().appName("TestSql").master("local[*]").enableHiveSupport().getOrCreate()
val df = spark.sql("select sepal_length,class from origin_csvload.csv_iris_qx  order by  sepal_length limit 10 ")
df.show(3)

代码100分

我们在数仓中新建了一张表origin_csvload.csv_iris_qx,然后通过SparkSQL执行了一条SQL,由于整个过程由于是懒加载的,需要通过Terminal方法触发,此处我们选择show方法来触发。

源码分析

词法解析、语法解析以及分析

sql方法会执行以下3个重点:

  1. sessionState.sqlParser.parsePlan(sqlText):将SQL字符串通过ANTLR解析成逻辑计划(Parsed Logical Plan)
  2. sparkSession.sessionState.executePlan(logicalPlan):执行逻辑计划,此处为懒加载,只新建QueryExecution实例,并不会触发实际动作。需要注意的是QueryExecution其实是包含了SQL解析执行的4个阶段计划(解析、分析、优化、执行)
  3. QueryExecution.assertAnalyzed():触发语法分析,得到分析计划(Analyzed Logical Plan)
代码100分def sql(sqlText: String): DataFrame = {
    //1:Parsed Logical Plan
    Dataset.ofRows(self, sessionState.sqlParser.parsePlan(sqlText))
}
  
def ofRows(sparkSession: SparkSession, logicalPlan: LogicalPlan): DataFrame = {
    val qe = sparkSession.sessionState.executePlan(logicalPlan)//d-1
    qe.assertAnalyzed()//d-2
    new Dataset[Row](sparkSession, qe, RowEncoder(qe.analyzed.schema))
}

//d-1
def executePlan(plan: LogicalPlan): QueryExecution = new QueryExecution(sparkSession, plan)

//2:Analyzed Logical Plan
lazy val analyzed: LogicalPlansparkSession.sessionState.analyzer.executeAndCheck(logical)

解析计划和分析计划

sql解析后计划如下:

== Parsed Logical Plan ==
'GlobalLimit 10
+- 'LocalLimit 10
   +- 'Sort ['sepal_length ASC NULLS FIRST], true
      +- 'Project ['sepal_length, 'class]
         +- 'UnresolvedRelation `origin_csvload`.`csv_iris_qx`

主要是将SQL一一对应地翻译成了catalyst的操作,此时数据表并没有被解析,只是简单地识别为表。而分析后的计划则包含了字段的位置、类型,表的具体类型(parquet)等信息。

代码100分== Analyzed Logical Plan ==
sepal_length: double, class: string
GlobalLimit 10
+- LocalLimit 10
   +- Sort [sepal_length#0 ASC NULLS FIRST], true
      +- Project [sepal_length#0, class#4]
         +- SubqueryAlias `origin_csvload`.`csv_iris_qx`
            +- Relation[sepal_length#0,sepal_width#1,petal_length#2,petal_width#3,class#4] parquet

此处有个比较有意思的点,UnresolvedRelation origin_csvload.csv_iris_qx被翻译成了一个子查询别名,读取文件出来的数据注册成了一个表,这个是不必要的,后续的优化会消除这个子查询别名。

优化以及执行

以DataSet的show方法为例,show的方法调用链为showString->getRows->take->head->withAction,我们先来看看withAction方法:

def head(n: Int): Array[T] = withAction("head", limit(n).queryExecution)(collectFromPlan)
private def withAction[U](name: String, qe: QueryExecution)(action: SparkPlan => U) = {
    val 
    result= SQLExecution.withNewExecutionId(sparkSession, qe) {
       action(qe.executedPlan)
    }
    result
}

withAction方法主要执行如下逻辑:
1. 拿到缓存的解析计划,使用遍历优化器执行解析计划,得到若干优化计划。
2. 获取第一个优化计划,遍历执行前优化获得物理执行计划,这是已经可以执行的计划了。
3. 执行物理计划,返回实际结果。至此,这条SQL之旅就结束了。

//3:Optimized Logical Plan,withCachedData为Analyzed Logical Plan,即缓存的变量analyzed
lazy val optimizedPlan: LogicalPlan = sparkSession.sessionState.optimizer.execute(withCachedData)
lazy val sparkPlan: SparkPlan = planner.plan(ReturnAnswer(optimizedPlan)).next()
//4:Physical Plan
lazy val executedPlan: SparkPlan = prepareForExecution(sparkPlan)

优化计划及物理计划

优化后的计划如下,可以看到SubqueryAliases已经没有了。

== Optimized Logical Plan ==
GlobalLimit 10
+- LocalLimit 10
   +- Sort [sepal_length#0 ASC NULLS FIRST], true
      +- Project [sepal_length#0, class#4]
         +- Relation[sepal_length#0,sepal_width#1,petal_length#2,petal_width#3,class#4] parquet

具体的优化点如下图所示,行首有!表示优化的地方。
优化点

其中”=== Result of Batch Finish Analysis ===”表示”Finish Analysis”的规则簇(参见附录一)被应用成功,可以看到该规则簇中有一个消除子查询别名的规则EliminateSubqueryAliases

Batch("Finish Analysis", Once,
      EliminateSubqueryAliases,
      ReplaceExpressions,
      ComputeCurrentTime,
      GetCurrentDatabase(sessionCatalog),
      RewriteDistinctAggregates)

最后根据物理计划生成规则(附录二)可以得到物理计划,这就是已经可以执行的计划了。具体如下:

== Physical Plan ==
TakeOrderedAndProject(limit=10, orderBy=[sepal_length#0 ASC NULLS FIRST], output=[sepal_length#0,class#4])
+- *(1) Project [sepal_length#0, class#4]
   +- *(1) FileScan parquet origin_csvload.csv_iris_qx[sepal_length#0,class#4] Batched: true, Format: Parquet, Location: CatalogFileIndex[hdfs://di124:8020/user/hive/warehouse/origin_csvload.db/csv_iris_qx], PartitionCount: 1, PartitionFilters: [], PushedFilters: [], ReadSchema: struct<sepal_length:double,class:string>

总结

本文简述了一条SQL是如何从字符串经过词法解析、语法解析、规则优化等步骤转化成可执行的物理计划,最后以一个Terminal方法触发逻辑返回结果。本文可为后续SQL优化提供一定思路,之后可再详述具体的SQL优化原则。

附录一:优化方法

分析计划会依次应用如下优化:

  1. 前置优化。当前为空。
  2. 默认优化。主要有如下类别,每个类别分别有若干优化规则。
  • Optimize Metadata Only Query
  • Extract Python UDFs
  • Prune File Source Table Partitions
  • Parquet Schema Pruning
  • Finish Analysis
  • Union
  • Subquery
  • Replace Operators
  • Aggregate
  • Operator Optimizations
  • Check Cartesian Products
  • Decimal Optimizations
  • Typed Filter Optimization
  • LocalRelation
  • OptimizeCodegen
  • RewriteSubquery
  1. 后置优化。当前为空。
  2. 用户提供的优化。来自experimentalMethods.extraOptimizations,当前也没有。

附录二:物理计划生成规则

生成物理执行计划的规则如下:

  • PlanSubqueries
  • EnsureRequirements
  • CollapseCodegenStages
  • ReuseExchange
  • ReuseSubquery

本文由博客一文多发平台 OpenWrite 发布!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/9830.html

(0)
上一篇 2023-01-31
下一篇 2023-01-31

相关推荐

  • JavaWeb——JDBC「建议收藏」

    JavaWeb——JDBC「建议收藏」内容索引 1. JDBC基本概念 2. 快速入门 3. 对JDBC中各个接口和类详解 JDBC: 1. 概念:Java DataBase Connectivity Java 数据库连接, Java语言

    2023-04-15
    162
  • 麒麟985性能测评,主流游戏没压力[通俗易懂]

    麒麟985性能测评,主流游戏没压力[通俗易懂]     荣耀30系列发布已经有一段时间,相信很多小伙伴对这款手机性能怎么样很好奇,毕竟荣耀30系列首发麒麟985处理器,一款全新的处理器出现在大家面前,肯定有很多疑问。今天笔者来带着大家看看麒麟9…

    2023-02-28
    146
  • 案例分析流程图_MySQL服务无法启动

    案例分析流程图_MySQL服务无法启动故障检测(Failure Detection)是 Group Replication 的一个核心功能模块,通过它可以及时识别集群中的故障节点,并将故障节点从集群中剔除掉。如果不将故障节点及时剔除的话,

    2023-06-14
    126
  • SQL之DDL、DML、DCL、TCL

    SQL之DDL、DML、DCL、TCL SQL SQL(structured query language)是一种领域特定语言(DSL,domain-specific language),用于管理关系型数据库(relational…

    2023-03-26
    141
  • Python数据爬虫实战

    Python数据爬虫实战在当今社交网络和互联网极度发达的时代,无论是企业还是个人都需要从海量数据中获取关键信息来指导决策。但是获取这些关键信息的过程通常需要大量的人力和时间成本,因此数据爬虫技术在这个时代显得尤为重要。Python作为一种流行的程序语言具有着领先的数据爬取与处理功能,在企业和个人应用中得到了很广泛的应用。

    2024-07-23
    33
  • MySQL必知必会–第十六章~第十七章[通俗易懂]

    MySQL必知必会–第十六章~第十七章[通俗易懂]第十六章–创建高级联结 1.使用表表别名 select cust_name, cust_contact from customers as c, orderitems as oi, orders …

    2023-02-16
    158
  • Python爬虫工具

    Python爬虫工具随着互联网的不断发展,爬虫技术成为了互联网领域一个非常热门的技术。而作为目前市面上最为流行和使用最广泛的编程语言之一,Python在爬虫领域也具有很大的优势,并且有着非常丰富的开源爬虫工具。本篇文章将从多个方面,详细介绍Python爬虫工具的有关知识。

    2024-07-05
    50
  • hdfs的ha机制_redis集群工作原理

    hdfs的ha机制_redis集群工作原理1.简单hdfs集群中存在的问题 不能存在两个NameNode 单节点问题 单节点故障转移 2.解决单节点问题 找额外一个NameNode备份原有的数据 会出现脑裂 脑裂:一个集群中多个管理者数据不一

    2022-12-30
    176

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注