【大数据】SparkSql连接查询中的谓词下推处理(一)

本文涉及的产品
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
简介: SparkSql 是架构在 Spark 计算框架之上的分布式 Sql 引擎,使用 DataFrame 和 DataSet 承载结构化和半结构化数据来实现数据复杂查询处理,提供的 DSL可以直接使用 scala 语言完成 Sql 查询,同时也使用  thriftserver 提供服务化的 Sql 查询功能。

本文首发于 vivo互联网技术 微信公众号 https://mp.weixin.qq.com/s/YPN85WBNcnhk8xKjTPTa2g

作者:李勇

目录:

1.SparkSql

2.连接查询和连接条件

3.谓词下推

4.内连接查询中的谓词下推规则

4.1.Join后条件通过AND连接

4.2.Join后条件通过OR连接

4.3.分区表使用OR连接过滤条件

1.SparkSql

SparkSql 是架构在 Spark 计算框架之上的分布式 Sql 引擎,使用 DataFrame 和 DataSet 承载结构化和半结构化数据来实现数据复杂查询处理,提供的 DSL可以直接使用 scala 语言完成 Sql 查询,同时也使用  thriftserver 提供服务化的 Sql 查询功能。

SparkSql 提供了 DataSource API ,用户通过这套 API 可以自己开发一套 Connector,直接查询各类数据源,数据源包括 NoSql、RDBMS、搜索引擎以及 HDFS 等分布式文件系统上的文件等。和 SparkSql 类似的系统有 Hive、PrestoDB 以及 Impala,这类系统都属于所谓的" Sql on Hadoop "系统,每个都相当火爆,毕竟在这个不搞 SQL 就是耍流氓的年代,没 SQL 确实很难找到用户使用。

2.连接查询和连接条件

Sql中的连接查询(join),主要分为内连接查询(inner join)、外连接查询(outter join)和半连接查询(semi join),具体的区别可以参考wiki的解释。

连接条件(join condition),则是指当这个条件满足时两表的两行数据才能"join"在一起被返回,例如有如下查询:

其中的"LT.id=RT.idAND LT.id>1"这部分条件被称为"join中条件",直接用来判断被join的两表的两行记录能否被join在一起,如果不满足这个条件,两表的这两行记录并非全部被踢出局,而是根据连接查询类型的不同有不同的处理,所以这并非一个单表的过滤过程或者两个表的的“联合过滤”过程;而where后的"RT.id>2"这部分被称为"join后条件",这里虽然成为"join后条件",但是并非一定要在join后才能去过滤数据,只是说明如果在join后进行过滤,肯定可以得到一个正确的结果,这也是我们后边分析问题时得到正确结果的基准方法。

3.谓词下推

所谓谓词(predicate),英文定义是这样的:A predicate is a function that returns bool (or something that can be implicitly converted to bool),也就是返回值是true或者false的函数,使用过scala或者spark的同学都知道有个filter方法,这个高阶函数传入的参数就是一个返回true或者false的函数。

但是如果是在sql语言中,没有方法,只有表达式。where后边的表达式起的作用正是过滤的作用,而这部分语句被sql层解析处理后,在数据库内部正是以谓词的形式呈现的。

那么问题来了,谓词为什么要下推呢? SparkSql中的谓词下推有两层含义,第一层含义是指由谁来完成数据过滤,第二层含义是指何时完成数据过滤。要解答这两个问题我们需要了解SparkSql的Sql语句处理逻辑,大致可以把SparkSql中的查询处理流程做如下的划分:

SparkSql首先会对输入的Sql语句进行一系列的分析(Analyse),包括词法解析(可以理解为搜索引擎中的分词这个过程)、语法分析以及语义分析(例如判断database或者table是否存在、group by必须和聚合函数结合等规则);之后是执行计划的生成,包括逻辑计划和物理计划。其中在逻辑计划阶段会有很多的优化,对谓词的处理就在这个阶段完成;而物理计划则是RDD的DAG图的生成过程;这两步完成之后则是具体的执行了(也就是各种重量级的计算逻辑,例如join、groupby、filter以及distinct等),这就会有各种物理操作符(RDD的Transformation)的乱入。

能够完成数据过滤的主体有两个,第一是分布式Sql层(在execute阶段),第二个是数据源。那么谓词下推的第一层含义就是指由Sql层的Filter操作符来完成过滤,还是由Scan操作符在扫描阶段完成过滤。

上边提到,我们可以通过封装SparkSql的Data Source API完成各类数据源的查询,那么如果底层数据源无法高效完成数据的过滤,就会执行全局扫描,把每条相关的数据都交给SparkSql的Filter操作符完成过滤,虽然SparkSql使用的Code Generation技术极大的提高了数据过滤的效率,但是这个过程无法避免大量数据的磁盘读取,甚至在某些情况下会涉及网络IO(例如数据非本地化存储时);如果底层数据源在进行扫描时能非常快速的完成数据的过滤,那么就会把过滤交给底层数据源来完成(至于哪些数据源能高效完成数据的过滤以及SparkSql又是如何完成高效数据过滤的则不是本文讨论的重点,会在其他系列的文章中介绍)。

那么谓词下推第二层含义,即何时完成数据过滤则一般是在指连接查询中,是先对单表数据进行过滤再和其他表连接还是在先把多表进行连接再对连接后的临时表进行过滤,则是本系列文章要分析和讨论的重点。

4.内连接查询中的谓词下推规则

假设我们有两张表,表结构很简单,数据也都只有两条,但是足以讲清楚我们的下推规则,两表如下,一个lefttable,一个righttable:

4.1.Join后条件通过AND连接

先来看一条查询语句:

这个查询是一个内连接查询,join后条件是用and连接的两个表的过滤条件,假设我们不下推,而是先做内连接判断,这时是可以得到正确结果的,步骤如下:

  1. 左表id为1的行在右表中可以找到,即这两行数据可以"join"在一起

  2. 左表id为2的行在右表中可以找到,这两行也可以"join"在一起

至此,join的临时结果表(之所以是临时表,因为还没有进行过滤)如下:

然后使用where条件进行过滤,显然临时表中的第一行不满足条件,被过滤掉,最后结果如下:

来看看先进行谓词下推的情况。先对两表进行过滤,过滤的结果分别如下:

然后再对这两个过滤后的表进行内连接处理,结果如下:

可见,这和先进行join再过滤得到的结果一致。

4.2.Join后条件通过OR连接

再来看一条查询语句:

我们先进行join处理,临时表的结果如下:

然后使用where条件进行过滤,最终查询结果如下:

如果我们先使用where条件后每个表各自的过滤条件进行过滤,那么两表的过滤结果如下:

然后对这两个临时表进行内连接处理,结果如下:

表格有问题吧,只有字段名,没有字段值,怎么回事?是的,你没看错,确实没有值,因为左表过滤结果只有id为1的行,右表过滤结果只有id为2的行,这两行是不能内连接上的,所以没有结果。

那么为什么where条件中两表的条件被or连接就会出现错误的查询结果呢?分析原因主要是因为,对于or两侧的过滤条件,任何一个满足条件即可以返回TRUE,那么对于"LT.value = 'two' OR RT.value = 'two' "这个查询条件,如果使用LT.value='two'把只有LT.value为'two'的左表记录过滤出来,那么对于左表中LT.value不为two的行,他们可能在跟右表使用id字段连接上之后,右表的RT.value恰好为two,也满足"LT.value = 'two' OR RT.value = 'two' ",但是可惜呀可惜,这行记录因为之前的粗暴处理,已经被过滤掉,结果就是得到了错误的查询结果。所以这种情况下谓词是不能下推的。

但是OR连接两表join后条件也有两个例外,这里顺便分析第一个例外。第一个例外是过滤条件字段恰好为Join字段,比如如下的查询:

在这个查询中,join后条件依然是使用OR连接两表的过滤条件,不同的是,join中条件不再是id相等,而是value字段相等,也就是说过滤条件字段恰好就是join条件字段。大家可以自行采用上边的分步法分析谓词下推和不下推时的查询结果,得到的结果是相同的。

我们来看看上边不能下推时出现的情况在这种查询里会不会出现。对于左表,如果使用LT.value='two'过滤掉不符合条件的其他行,那么因为join条件字段也是value字段,说明在左表中LT.value不等于two的行,在右表中也不能等于two,否则就不满足"LT.value=RT.value"了。这里其实有一个条件传递的过程,通过join中条件,已经在逻辑上提前把两表整合成了一张表。

至于第二个例外,则涉及了SparkSql中的一个优化,所以需要单独介绍。

4.3.分区表使用OR连接过滤条件

如果两个表都是分区表,会出现什么情况呢?我们先来看如下的查询:

此时左表和右表都不再是普通的表,而是分区表,分区字段是pt,按照日期进行数据分区。同时两表查询条件依然使用OR进行连接。试想,如果不能提前对两表进行过滤,那么会有非常巨量的数据要首先进行连接处理,这个代价是非常大的。但是如果按照我们在2中的分析,使用OR连接两表的过滤条件,又不能随意的进行谓词下推,那要如何处理呢?SparkSql在这里使用了一种叫做“分区裁剪”的优化手段,即把分区并不看做普通的过滤条件,而是使用了“一刀切”的方法,把不符合查询分区条件的目录直接排除在待扫描的目录之外。

我们知道分区表在HDFS上是按照目录来存储一个分区的数据的,那么在进行分区裁剪时,直接把要扫描的HDFS目录通知Spark的Scan操作符,这样,Spark在进行扫描时,就可以直接咔嚓掉其他的分区数据了。但是,要完成这种优化,需要SparkSql的语义分析逻辑能够正确的分析出Sql语句所要表达的精确目的,所以分区字段在SparkSql的元数据中也是独立于其他普通字段,进行了单独的标示,就是为了方便语义分析逻辑能区别处理Sql语句中where条件里的这种特殊情况。

相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps 
目录
相关文章
|
14天前
|
存储 SQL 分布式计算
Java连接阿里云MaxCompute例
要使用Java连接阿里云MaxCompute数据库,首先需在项目中添加MaxCompute JDBC驱动依赖,推荐通过Maven管理。避免在代码中直接写入AccessKey,应使用环境变量或配置文件安全存储。示例代码展示了如何注册驱动、建立连接及执行SQL查询。建议使用RAM用户提升安全性,并根据需要配置时区和公网访问权限。具体步骤和注意事项请参考阿里云官方文档。
|
30天前
|
关系型数据库 MySQL 分布式数据库
PolarDB 并行查询问题之大数据量的实时分析查询挑战如何解决
PolarDB 并行查询问题之大数据量的实时分析查询挑战如何解决
28 2
|
2月前
|
SQL 分布式计算 DataWorks
MaxCompute产品使用合集之针对MaxCompute查询结果排队问题,该如何优化
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
59 10
|
2月前
|
JSON 分布式计算 大数据
MaxCompute操作报错合集之连接环境时,出现报错:TypeError: access_id and secret_access_key,该怎么解决
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
2月前
|
SQL 机器学习/深度学习 分布式计算
MaxCompute产品使用合集之怎么使用SQL查询来获取ODPS中所有的表及字段信息
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
2月前
|
SQL 分布式计算 数据处理
MaxCompute操作报错合集之使用Spark查询时函数找不到的原因是什么
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
2月前
|
分布式计算 资源调度 DataWorks
MaxCompute操作报错合集之出现“查询运行日志失败”的报错,一般是什么导致的
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
2月前
|
SQL 分布式计算 DataWorks
MaxCompute操作报错合集之使用sql查询一个表的分区数据时遇到报错,该如何解决
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
2月前
|
分布式计算 大数据 数据挖掘
MaxCompute产品使用合集之如何解决MC通过外部表方式访问Hologres时,数据量达到3000万条左右导致查询速度慢
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
2月前
|
机器学习/深度学习 分布式计算 DataWorks
MaxCompute产品使用合集之使用临时查询创建的表,在表管理和公共表没有找到,是什么原因
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。

热门文章

最新文章