hive谓词下放

2023-10-04 02:10
文章标签 hive 谓词 下放

本文主要是介绍hive谓词下放,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

保留表(Preserved Row table)

在outer join中需要返回所有数据的表叫做保留表,也就是说在left outer join中,左表需要返回所有数据,则左表是保留表;right outer join中右表则是保留表;在full outer join中左表和右表都要返回所有数据,则左右表都是保留表。

Null Supplying table

在outer join中对于没有匹配到的行需要用null来填充的表称为Null Supplying table。在left outer join中,左表的数据全返回,对于左表在右表中无法匹配的数据的相应列用null表示,则此时右表是Null Supplying table,相应的如果是right outer join的话,左表是Null Supplying table。但是在full outer join中左表和右表都是Null Supplying table,因为左表和右表都会用null来填充无法匹配的数据。

此时你会发现full outer join就是个矛盾体,因为此时的左表和右表即使保留表又是Null Supplying table,这就导致在outer join中谓词下放时有一些问题。

Join中的谓词

Join中的谓词是指 Join On语句中的谓词。如:’R1 join R2 on R1.x = 5’ the predicate ‘R1.x = 5’是Join中的谓词

Join之后的谓词

where语句中的谓词称之为Join之后的谓词

谓词下放

谓词:谓词是一个属性或是一个表示“持有”或“不持有”的表达式,换句话说,也就是取值为 TRUE、FALSE 或 UNKNOWN 的表达式。谓词用于 WHERE 子句和 HAVING 子句的搜索条件中,还用于 FROM 子句的联接条件以及需要布尔值的其他构造中。

对于outer join中的坑,主要是对谓词下放的规则不熟悉,导致理解的不够全面,造成一些坑。
谓词下放的规则有两个,分别为

1.Join中谓词如果是保留表的,则不会下放。
2.Join之后的谓词如果是Null Supplying tables的,则不会下放。

栗子

创建表

create table t1 (id int, name string) ROW FORMAT DELIMITED FIELDS TERMINATED BY “,”;
create table t2 (id int, name string) ROW FORMAT DELIMITED FIELDS TERMINATED BY “,”;

t1里的数据如下:

1,a
1,b
2,a
2,b
3,a
3,b
4,b

t2里的数据如下:

1,aa
4,dd

在执行例子之前,避免map join影响到各个例子的执行计划,先关闭map join,set hive.auto.convert.join=false;

demo1:

select t1.*,t2.name as name_t2 
from t1 
left outer join t2 
on (t1.id=t2.id) 
where t1.name='a' and t2.name='aa';

此sql中,保留表为t1,Null Supplying table为t2,join中谓词在此sql中没有,where中的两个谓词都是join之后的谓词。
则根据谓词下放规则,t1.name='a'是保留表的字段,则被下放,而t2.name='aa'是Null Supplying table的,Null Supplying table不支持join之后的谓词下放。
那么此时的sql就等同于

select t.*,t2.name as name_t2 from (select id, name from t1 where t1.name='a') as t left outer join t2 on(t.id=t2.id) where t2.name='aa';

其结果为:

1 a aa

造成这样的结果是因为hive中outer join谓词下放的规则,sql中的t2.name='aa'是join之后的谓词,不会被下放到t2中(t2是Null Supplying table),而是对t1和t2 join的结果进行filter,filter的条件是t2.name='aa',于是就出现了1 a aa结果,因为其余数据的t2.name的值都为NULL</p>
首先sql中有两个join之后的谓词,分别为t1.name='a' and t2.name='aa',其中t1.name是保留表t1的,会谓词下放,在scan t1表时,对t1中的数据进行过滤,t2.name是t2的,t2不是保留表,谓词无法下放,而where又是在join之后执行的(Joins occur BEFORE WHERE CLAUSES)。看下sql的执行计划:</p>

STAGE DEPENDENCIES:Stage-1 is a root stageStage-0 depends on stages: Stage-1STAGE PLANS:Stage: Stage-1Map ReduceMap Operator Tree:TableScanalias: t1Statistics: Num rows: 5 Data size: 28 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (name = 'a') (type: boolean)Statistics: Num rows: 2 Data size: 11 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 2 Data size: 11 Basic stats: COMPLETE Column stats: NONETableScanalias: t2Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEvalue expressions: name (type: string)Reduce Operator Tree:Join Operatorcondition map:Left Outer Join0 to 1keys:0 id (type: int)1 id (type: int)outputColumnNames: _col0, _col6Statistics: Num rows: 2 Data size: 12 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (_col6 = 'aa') (type: boolean)Statistics: Num rows: 1 Data size: 6 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: int), 'a' (type: string), 'aa' (type: string)outputColumnNames: _col0, _col1, _col2Statistics: Num rows: 1 Data size: 6 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 1 Data size: 6 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.TextInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink

从sql的执行计划上也可以看出,TableScan t1时使用了predicate: (name = 'a') (type: boolean)对数据进行过滤,(则进入mr的t1数据不是全表数据,而是过滤过的数据)。而where对应的filter operator是在join之后才执行的
demo2:

select t1.*,t2.name as name_t2 
from t1 
left outer join t2 
on (t1.id=t2.id and t2.name='aa') w
here t1.name='a';

执行结果为:

 1  a   aa2  a   NULL3  a   NULL

其中t2.name是join中谓词,t1.name是join之后谓词,根据规则join中谓词能下放到t2中,join之后的谓词能下放到t1中,则上面sql的意思是将t1中name为a的数据与t2中name为aa的数据进行join,t1和t2都会在table scan时进行数据过滤。sql的执行计划如下:

STAGE DEPENDENCIES:Stage-1 is a root stageStage-0 depends on stages: Stage-1STAGE PLANS:Stage: Stage-1Map ReduceMap Operator Tree:TableScanalias: t1Statistics: Num rows: 5 Data size: 28 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (name = 'a') (type: boolean)Statistics: Num rows: 2 Data size: 11 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 2 Data size: 11 Basic stats: COMPLETE Column stats: NONETableScanalias: t2Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (name = 'aa') (type: boolean)Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEvalue expressions: name (type: string)Reduce Operator Tree:Join Operatorcondition map:Left Outer Join0 to 1keys:0 id (type: int)1 id (type: int)outputColumnNames: _col0, _col6Statistics: Num rows: 2 Data size: 12 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: int), 'a' (type: string), _col6 (type: string)outputColumnNames: _col0, _col1, _col2Statistics: Num rows: 2 Data size: 12 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 2 Data size: 12 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.TextInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink

从执行计划上可以看出t1和t2的TableScan中都存在Filter Operator操作,对数据进行过滤。
demo3:

select t1.*,t2.name as name_t2 from t1 left outer join t2 on (t1.id=t2.id and t1.name='a' ) where t2.name='aa';

此sql中有两个谓词,一个是join中谓词t1.name='a'和join之后谓词t2.name='aa'。
这里需要明白一点,join中谓词决定了进行join的数据,join之后谓词决定了最终要呈现的数据。也就是说join中谓词t1.name='a'决定了t1表中name为a的数据才去和t2进行join,而join之后谓词t2.name='aa'决定了最终的结果。
执行结果为:

1 a aa

这里的结果随便和case 1的结果一样,但是执行的内部逻辑是不一样的,case3在执行where filter之前返回的数据是t1全表的数据,而case1在执行where filter之前返回的数据是t1中name为a的数据,因为case3中join中谓词t1.name='a'并不能对t1进行下放,这里的语义是对t1进行全表扫描,只拿name为a的数据和t2进行join,id匹配成功则为t2.name的值,匹配不成功和name不为a的数据中t2.name的值都为NULL,join结束之后由where filter过滤t2.name='aa',因此就出现了上面的结果(因为没有匹配成功的和没有进行匹配的数据都是NULL,被过滤)。

STAGE DEPENDENCIES:Stage-1 is a root stageStage-0 depends on stages: Stage-1STAGE PLANS:Stage: Stage-1Map ReduceMap Operator Tree:TableScanalias: t1Statistics: Num rows: 1 Data size: 28 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 1 Data size: 28 Basic stats: COMPLETE Column stats: NONEvalue expressions: name (type: string)TableScanalias: t2Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEvalue expressions: name (type: string)Reduce Operator Tree:Join Operatorcondition map:Left Outer Join0 to 1filter predicates:0 {(VALUE._col0 = 'a')}1keys:0 id (type: int)1 id (type: int)outputColumnNames: _col0, _col1, _col6Statistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (_col6 = 'aa') (type: boolean)Statistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: int), _col1 (type: string), 'aa' (type: string)outputColumnNames: _col0, _col1, _col2Statistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.TextInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink

上面是demo3的执行计划,可以看出两个表在TableScan时都是全表扫描,没有进行filter,在join时有个filterfilter predicates,join结束之后又有个Filter Operator对join的结果进行过滤。
demo4:

select t1.*,t2.name as name_t2 from t1 left outer join t2 on (t1.id=t2.id and t1.name='a' and t2.name='aa');

此sql中只有join中谓词,根据规则t1.name=’a’不能下放到t1中,而t2.name=’aa’能够下放到t2中,那就是说扫t1的全表数据,然后拿t1.name为a的数据去和t2中t2.name为aa的数据(t2在table scan时会过滤name为aa的数据)进行join,那么t1中name不为a的数据不和t2进行join,直接将t2.name置为NULL,而t1中name为a却没有和t2进行join成功的数据也为NULL,所以其结果如下:

 1  b   NULL1  a   aa2  b   NULL2  a   NULL3  b   NULL3  a   NULL4  b   NULL

这里需要说明下,t1是保留表,join之后要返回其表中所有的数据,因为在join之后没有where对其结果进行过滤,所以此处显示的是t1表的所有数据,上面的case之所以没有返回t1的所有数据是因为他们要么在table scan时进行了过滤要么就是在join之后通过where进行了过滤

为了验证下t1中只有那么为a的数据与t2进行了join,我对t2中的数据进行了修改,添加一条数据4,aa,其执行结果按照上面的逻辑应该不会发生变化,再次执行case4,看下返回的结果是否一致。其结果如下:

  1 b   NULL1 a   aa2 b   NULL2 a   NULL3 b   NULL3 a   NULL4 b   NULL

与上面的结果一致。
此sql的执行计划如下:

STAGE DEPENDENCIES:Stage-1 is a root stageStage-0 depends on stages: Stage-1STAGE PLANS:Stage: Stage-1Map ReduceMap Operator Tree:TableScanalias: t1Statistics: Num rows: 1 Data size: 28 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 1 Data size: 28 Basic stats: COMPLETE Column stats: NONEvalue expressions: name (type: string)TableScanalias: t2Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (name = 'aa') (type: boolean)Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONEvalue expressions: name (type: string)Reduce Operator Tree:Join Operatorcondition map:Left Outer Join0 to 1filter predicates:0 {(VALUE._col0 = 'a')}1keys:0 id (type: int)1 id (type: int)outputColumnNames: _col0, _col1, _col6Statistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: int), _col1 (type: string), _col6 (type: string)outputColumnNames: _col0, _col1, _col2Statistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.TextInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink

这四个case介绍了left outer join的情况,right outer join与left类似,只是保留表和Null Supplying table换下位置,比较特殊的是full outer join,在full outer join中join中谓词和join之后谓词都不会被下放,(这里说不会下放可能不太准备,会下放,但是下放的位置不对,下放前和下放后的位置是一样的,开启log可以查看。)

因为full outer join中的两个表既是保留表也是Null Supplying table。来看个full outer join的例子,

 select t1.*,t2.name as name_t2 from t1 full outer join t2 on (t1.id=t2.id and t2.name='aa') where t1.name='a';

其结果为

  1 a   aa2 a   NULL3 a   NULL

其sql的执行计划如下:

  STAGE PLANS:Stage: Stage-1Map ReduceMap Operator Tree:TableScanalias: t1Statistics: Num rows: 1 Data size: 28 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 1 Data size: 28 Basic stats: COMPLETE Column stats: NONEvalue expressions: name (type: string)TableScanalias: t2Statistics: Num rows: 1 Data size: 15 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: id (type: int)sort order: +Map-reduce partition columns: id (type: int)Statistics: Num rows: 1 Data size: 15 Basic stats: COMPLETE Column stats: NONEvalue expressions: name (type: string)Reduce Operator Tree:Join Operatorcondition map:Outer Join 0 to 1filter predicates:01 {(VALUE._col0 = 'aa')}keys:0 id (type: int)1 id (type: int)outputColumnNames: _col0, _col1, _col6Statistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (_col1 = 'a') (type: boolean)Statistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: int), 'a' (type: string), _col6 (type: string)outputColumnNames: _col0, _col1, _col2Statistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 1 Data size: 30 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.TextInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink

从执行计划中可以看出t1和t2在scan时都没有进行filter过滤,也就是说join中谓词和join之后的谓词都没有进行下放,join中谓词是在Join Operator时通过filter predicates进行过滤join,而join之后谓词是在join之后通过Filter Operator进行过滤的。

如果t1和t2某个表是分区表,此时想只full outer join某个分区的数据,应该怎么过滤更高效呢?
此时应该使用子查询,sql为select t1.*,t2.name as name_t2 from t1 full outer join t2 on (t1.id=t2.id and t2.name='aa')

select t.*,t2.name as name_t2 from(select * from t1 where day='20170411') tfull outer join  t2on t.id=t2.id

转载:hive outer join 之谓词下放

这篇关于hive谓词下放的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1103

相关文章

Hive和Hbase的区别

Hive 和 HBase 都是 Hadoop 生态系统中的重要组件,它们都能处理大规模数据,但各自有不同的适用场景和设计理念。以下是两者的主要区别: 1. 数据模型 Hive:Hive 类似于传统的关系型数据库 (RDBMS),以表格形式存储数据。它使用 SQL-like 语言 HiveQL 来查询和处理数据,数据通常是结构化或半结构化的。HBase:HBase 是一个 NoSQL 数据库,基

掌握Hive函数[2]:从基础到高级应用

目录 高级聚合函数 多进一出 1. 普通聚合 count/sum... 2. collect_list 收集并形成list集合,结果不去重 3. collect_set 收集并形成set集合,结果去重  案例演示 1. 每个月的入职人数以及姓名  炸裂函数  概述  案例演示 1. 数据准备 1)表结构 2)建表语句 3)装载语句 2. 需求 1)需求说明 2)答

【Hive Hbase】Hbase与Hive的区别与联系

问题导读: Hive与Hbase的底层存储是什么? hive是产生的原因是什么? habase是为了弥补hadoop的什么缺陷? 共同点: 1.hbase与hive都是架构在hadoop之上的。都是用hadoop作为底层存储 区别: 2.Hive是建立在Hadoop之上为了减少MapReduce jobs编写工作的批处理系统,HBase是为了支持弥补Hadoop对实时操作的缺陷的项目

【hive 日期转换】Hive中yyyymmdd和yyyy-mm-dd日期之间的切换

方法1: from_unixtime+ unix_timestamp--20171205转成2017-12-05 select from_unixtime(unix_timestamp('20171205','yyyymmdd'),'yyyy-mm-dd') from dual;--2017-12-05转成20171205select from_unixtime(unix_timestamp

【hive 函数】Hive分析函数和窗口函数

拿一个例子来说 数据集: cookie1,2015-04-10 10:00:02,url2 cookie1,2015-04-10 10:00:00,url1 cookie1,2015-04-10 10:03:04,1url3 cookie1,2015-04-10 10:50:05,url6 cookie1,2015-04-10 11:00:00,url7 cookie1,2

Hive SQL 分组与连接操作详解

目录 分组 Group By语句 1. 案例实操  Having语句 1. having 与 where 不同点 2. 案例实操  Join语句  等值Join 1. 案例实操  表的别名 1. 好处 2. 案例实操  内连接  左外连接  右外连接  满外连接  多表连接 1. 创建位置表 2. 导入数据 3. 多表连接查询  笛卡尔集 1. 笛卡尔集

Hive SQL基础语法及查询实践

目录 基础语法 1. 官网地址 2. 查询语句语法  基本查询(Select…From)  数据准备 (0)原始数据 (1)创建部门表 (2)创建员工表 (3)导入数据  全表和特定列查询 1. 全表查询 2. 选择特定列查询  列别名 1. 重命名一个列 2. 便于计算 3. 紧跟列名,也可以在列名和别名之间加入关键字 ‘AS’ 案例实操  Limit语句

Hive是什么?

Apache Hive 是一个基于 Hadoop 的数据仓库工具,用于在 Hadoop 分布式文件系统(HDFS)上管理和查询大规模结构化数据集。Hive 提供了一个类似 SQL 的查询语言,称为 HiveQL,通过这种语言可以在 HDFS 上执行 MapReduce 作业而无需编写复杂的代码。 Hive 的核心概念和特点 数据仓库工具:Hive 可以将结构化数据存储在 HDFS 上,用户可

Hive扩展功能(一)--Parquet

软件环境: linux系统: CentOS6.7Hadoop版本: 2.6.5zookeeper版本: 3.4.8 主机配置: 一共m1, m2, m3这三部机, 每部主机的用户名都为centos 192.168.179.201: m1 192.168.179.202: m2 192.168.179.203: m3 m1: Zookeeper, Namenode, DataNod

Hive - 日期从整形转为Date类型

在建表的时候我们常将日期字段设置为INT类型,将诸如20180601这样的数字值来表示日期,这样在做日期比较等操作时没有问题,但是要进行某些日期计算,就要先转成日期类型才能进行计算了,怎么转换呢? 数据准备 下面在Hive中先建一个表,含有一个INT类型的日期字段,插入两行数据。 create table tb (dt INT);insert into tb values (2018070