sparkSQL1.1入门之四:深入了解sparkSQL执行计划
前面两章花了不少篇幅介绍了SparkSQL的执行过程,非常多读者还是认为当中的概念非常抽象。比方Unresolved LogicPlan、LogicPlan、PhysicalPlan是长得什么样子,没点印象。仅仅知道名词,感觉非常缥缈。
本章就着重介绍一个工具hive/console,来加深读者对sparkSQL的执行计划的理解。
该工具是给开发人员使用,在编译生成的安装部署包中并没有;该工具须要使用sbt编译执行。要使用该工具,须要具备下面条件:
- spark1.1.0源代码
- hive0.12源代码并编译
- 配置环境变量
ant clean package -Dhadoop.version=2.2.0 -Dhadoop-0.23.version=2.2.0 -Dhadoop.mr.rev=23
export HIVE_HOME=/app/hadoop/hive012/src/build/dist
export HIVE_DEV_HOME=/app/hadoop/hive012/src
export HADOOP_HOME=/app/hadoop/hadoop220
D:启动
sbt/sbt hive/console
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
在控制台的scala提示符下,输入:help能够获取帮助,输入Tab键会陈列出当前可用的方法、函数、及变量。下图为按Tab键时显示的方法和函数。随着用户不断使用该控制态,用户定义或使用过的变量也会陈列出来。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
/*源自 sql/hive/src/main/scala/org/apache/spark/sql/hive/TestHive.scala */
// The test tables that are defined in the Hive QTestUtil.
// /itests/util/src/main/java/org/apache/hadoop/hive/ql/QTestUtil.java
val hiveQTestUtilTables = Seq(
TestTable("src",
"CREATE TABLE src (key INT, value STRING)".cmd,
s"LOAD DATA LOCAL INPATH '${getHiveFile("data/files/kv1.txt")}' INTO TABLE src".cmd),
TestTable("src1",
"CREATE TABLE src1 (key INT, value STRING)".cmd,
s"LOAD DATA LOCAL INPATH '${getHiveFile("data/files/kv3.txt")}' INTO TABLE src1".cmd),
TestTable("srcpart", () => {
runSqlHive(
"CREATE TABLE srcpart (key INT, value STRING) PARTITIONED BY (ds STRING, hr STRING)")
for (ds <- Seq("2008-04-08", "2008-04-09"); hr <- Seq("11", "12")) {
runSqlHive(
s"""LOAD DATA LOCAL INPATH '${getHiveFile("data/files/kv1.txt")}'
|OVERWRITE INTO TABLE srcpart PARTITION (ds='$ds',hr='$hr')
""".stripMargin)
}
}),
......
)
由于要使用hive0.12的測试数据。所以须要定义两个环境变量:HIVE_HOME和HIVE_DEV_HOME。假设使用hive0.13的话。用户须要更改到对应文件夹:
/*源自 sql/hive/src/main/scala/org/apache/spark/sql/hive/TestHive.scala */
/** The location of the compiled hive distribution */
lazy val hiveHome = envVarToFile("HIVE_HOME")
/** The location of the hive source code. */
lazy val hiveDevHome = envVarToFile("HIVE_DEV_HOME")
/* 源自 project/SparkBuild.scala */
object Hive {
lazy val settings = Seq(
javaOptions += "-XX:MaxPermSize=1g",
// Multiple queries rely on the TestHive singleton. See comments there for more details.
parallelExecution in Test := false,
// Supporting all SerDes requires us to depend on deprecated APIs, so we turn off the warnings
// only for this subproject.
scalacOptions <<= scalacOptions map { currentOpts: Seq[String] =>
currentOpts.filterNot(_ == "-deprecation")
},
initialCommands in console :=
"""
|import org.apache.spark.sql.catalyst.analysis._
|import org.apache.spark.sql.catalyst.dsl._
|import org.apache.spark.sql.catalyst.errors._
|import org.apache.spark.sql.catalyst.expressions._
|import org.apache.spark.sql.catalyst.plans.logical._
|import org.apache.spark.sql.catalyst.rules._
|import org.apache.spark.sql.catalyst.types._
|import org.apache.spark.sql.catalyst.util._
|import org.apache.spark.sql.execution
|import org.apache.spark.sql.hive._
|import org.apache.spark.sql.hive.test.TestHive._
|import org.apache.spark.sql.parquet.ParquetTestData""".stripMargin
)
}
2:经常使用操作
//在控制台逐行执行
case class Person(name:String, age:Int, state:String)
sparkContext.parallelize(Person("Michael",29,"CA")::Person("Andy",30,"NY")::Person("Justin",19,"CA")::Person("Justin",25,"CA")::Nil).registerTempTable("people")
val query= sql("select * from people")
query.printSchema
query.queryExecution
query.queryExecution.logical
query.queryExecution.analyzed
2.5 查看优化后的LogicalPlan
query.queryExecution.optimizedPlan
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
query.queryExecution.sparkPlan
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
query.toDebugString
以下看看这些数据源的schema:
{
"fullname": "Sean Kelly",
"org": "SK Consulting",
"emailaddrs": [
{"type": "work", "value": "kelly@seankelly.biz"},
{"type": "home", "pref": 1, "value": "kelly@seankelly.tv"}
],
"telephones": [
{"type": "work", "pref": 1, "value": "+1 214 555 1212"},
{"type": "fax", "value": "+1 214 555 1213"},
{"type": "mobile", "value": "+1 214 555 1214"}
],
"addresses": [
{"type": "work", "format": "us",
"value": "1234 Main StnSpringfield, TX 78080-1216"},
{"type": "home", "format": "us",
"value": "5678 Main StnSpringfield, TX 78080-1316"}
],
"urls": [
{"type": "work", "value": "http://seankelly.biz/"},
{"type": "home", "value": "http://seankelly.tv/"}
]
}
去空格和换行符后保存为/home/mmicky/data/nestjson.json,使用jsonFile读入并注冊成表jsonPerson,然后定义一个查询jsonQuery:
jsonFile("/home/mmicky/data/nestjson.json").registerTempTable("jsonPerson")
val jsonQuery = sql("select * from jsonPerson")
jsonQuery.printSchema
jsonQuery.queryExecution
parquetFile("/home/mmicky/data/spark/wiki_parquet").registerTempTable("parquetWiki")
val parquetQuery = sql("select * from parquetWiki")
parquetQuery.printSchema
查询parquetQuery的整个执行计划:
parquetQuery.queryExecution
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
以下我们使用sales表看看其schema和整个执行计划。首先定义一个查询hiveQuery:
val hiveQuery = sql("select * from sales")
hiveQuery.printSchema
查看hiveQuery的整个执行计划:
hiveQuery.queryExecution
从上面能够看出,来自jsonFile、parquetFile、hive数据的物理计划还有有非常大差别的。
sql("select state,avg(age) from people group by state").queryExecution
sql("select state,avg(age) from people group by state").toDebugString
sql("select a.name,b.name from people a join people b where a.name=b.name").queryExecution
sql("select a.name,b.name from people a join people b where a.name=b.name").toDebugString
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
sql("select distinct a.name,b.name from people a join people b where a.name=b.name").queryExecution
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
sql("select distinct a.name,b.name from people a join people b where a.name=b.name").toDebugString
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
sql("select name from (select * from people where age >=19) a where a.age <30").queryExecution
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
上面的查询,在Optimized的过程中。将age>=19和age<30这两个Filter合并了,合并成((age>=19) && (age<30))。事实上上面还做了一个其它的优化,就是project的下推,子查询使用了表的全部列,而主查询使用了列name。在查询数据的时候子查询优化成仅仅查列name。
sql("select name from (select name,state as location from people) a where location='CA'").queryExecution
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
sql("select name,1+2 from people").queryExecution
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
在Optimized的过程中,将常量表达式直接累加在一起。用新的列名来表示。
object CombineFilters extends Rule[LogicalPlan] {
def apply(plan: LogicalPlan): LogicalPlan = plan transform {
case Filter(c1, Filter(c2, grandChild)) =>
Filter(And(c1,c2),grandChild)
}
}
val query= sql("select * from people").where('age >=19).where('age <30)
query.queryExecution.analyzed
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
最后。使用自己定义优化函数进行优化:
CombineFilters(query.queryExecution.analyzed)
能够看到两个Filter合并在一起了。
val hiveQuery = sql("SELECT * FROM (SELECT * FROM src) a")
hiveQuery.queryExecution.analyzed
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
然后,直接用transform将自己定义的rule:
hiveQuery.queryExecution.analyzed transform {
case Project(projectList, child) if projectList == child.output => child
}
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYm9va19tbWlja3k=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
该transform在LogicPlan的主查询和子查询的project同样时合并project。
sparkSQL1.1入门之四:深入了解sparkSQL执行计划的更多相关文章
- sparkSQL1.1入门之二:sparkSQL执行架构
在介绍sparkSQL之前.我们首先来看看,传统的关系型数据库是怎么执行的.当我们提交了一个非常easy的查询: SELECT a1,a2,a3 FROM tableA Where con ...
- Spark入门实战系列--6.SparkSQL(上)--SparkSQL简介
[注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .SparkSQL的发展历程 1.1 Hive and Shark SparkSQL的前身是 ...
- sparkSQL1.1入门
http://blog.csdn.net/book_mmicky/article/details/39288715 2014年9月11日,Spark1.1.0忽然之间发布.笔者立即下载.编译.部署了S ...
- sparkSQL1.1入门之十:总结
回想一下,在前面几章中,就sparkSQL1.1.0基本概念.执行架构.基本操作和有用工具做了基本介绍. 基本概念: SchemaRDD Rule Tree LogicPlan Parser Anal ...
- VS2010/MFC编程入门之四(MFC应用程序框架分析)
VS2010/MFC编程入门之四(MFC应用程序框架分析)-软件开发-鸡啄米 http://www.jizhuomi.com/software/145.html 上一讲鸡啄米讲的是VS2010应用 ...
- JBPM4入门——9.自动节点单线执行
JBPM入门系列文章: JBPM4入门——1.jbpm简要介绍 JBPM4入门——2.在eclipse中安装绘制jbpm流程图的插件 JBPM4入门——3.JBPM4开发环境的搭建 JBPM4入门—— ...
- oracle查看执行计划入门
基于Oracle的应用系统很多的性能问题都是由应用系统的SQL性能低劣引起的,因此SQL的性能优化非常重要.要分析与优化SQL的性能,一般是通过查看该SQL的执行计划,然后通过执行计划有针对性地对SQ ...
- sql server 执行计划(execution plan)介绍
大纲:目的介绍sql server 中执行计划的大致使用,当遇到查询性能瓶颈时,可以发挥用处,而且带有比较详细的学习文档和计划,阅读者可以按照我计划进行,从而达到对执行计划一个比较系统的学习. 什么是 ...
- SQL优化 MySQL版 -分析explain SQL执行计划与Extra
Extra 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 注:此文章必须有一定的Mysql基础,或观看执行计划入门篇传送门: https:.html 终于总结到哦SQK执行计划的最 ...
随机推荐
- linux常见题目
1. 把一个文件里面所有包含 abc 的行里面的 abc 替换成 def,然后输出第一列和第三列 cat abc.txt | grep abc | sed 's/abc/def/g' | awk '{ ...
- java面试第十天
JFC:java基础类库(具体的类可以查看API文档) 观察者模式: 事件监听者对事件源进行监听,事件源会发生某些事件,监听者需要对事件作出相应的处理. 事件监听者(Observer): 处理事件 事 ...
- 关于SimHash去重原理的理解(能力工场小马哥)
阅读目录 1. SimHash与传统hash函数的区别 2. SimHash算法思想 3. SimHash流程实现 4. SimHash签名距离计算 5. SimHash存储和索引 6. SimHas ...
- Ubuntu 下iscsi initiator的安装与使用
Ubuntu下比较方便好用的initiator是open iscsi,这里将要简要介绍它的使用方法: 1.安装: sudo apt-get install open-iscsi 2.chap设置 如果 ...
- 编译时:virtual memory exhausted: Cannot allocate memory(转)
一.问题 当安装虚拟机时系统时没有设置swap大小或设置内存太小,编译程序会出现virtual memory exhausted: Cannot allocate memory的问题,可以用swap扩 ...
- UVa 1303 - Wall
题目:有非常多点.修一座最短的围墙把素有点围起来,使得全部点到墙的距离不小于l. 分析:计算几何,凸包. 假设.没有距离l的限制.则答案就是凸包的周长了.有了距离限制事实上是添加了2*π*l. 证明: ...
- sql遍历全部数据集
DECLARE @a int set @a = 1 while @a < 5 BEGIN select top(1) * from QPShuGameMatchDB..MatchScoreSta ...
- 5、main方法详解
public class HelloWorld { public static void main(String[] args){ System.out.print("Hello World ...
- CitrixSmartAuditor安装报错解决方法
报错1:安装过程中报错 解决方法: SQLServer的配置: http://www.cnblogs.com/weizhengLoveMayDay/p/3267756.html 报错2:无法连接到Sm ...
- 深入PHP内核之数组
定义: PHP 中的数组实际上是一个有序映射.映射是一种把 values 关联到 keys 的类型.此类型在很多方面做了优化,因此可以把它当成真正的数组,或列表(向量),散列表(是映射的一种实现),字 ...