关于 HiveSQL 常见的 Left Join 误区,你知道吗

写在前面

很多时候,由于SQL逻辑复杂,加之对SQL执行逻辑理解不透彻,很容易产生一些莫名其妙的结果,这些结果看似不符合预期,殊不知这就是真实结果。本文整理了几个常见的SQL问题,我们在实际书写SQL脚本时,需要多加注意,希望本文对你有所帮助。

关于LEFT JOIN

外连接是我们书写SQL时经常使用的多表连接方式,使用起来也是十分的简单。值得注意的是,越是简单的东西,越是容易被忽略细节。通常我们都是这样理解LEFT JOIN的:

语义是满足Join on条件的直接返回,但不满足情况下,需要返回Left Outer Join的left 表所有列,同时右表的列全部填null

上述对于LEFT JOIN的理解是没有任何问题的,但是里面有一个误区:谓词下推。具体看下面的实例:

假设有如下的三张表:

--建表
createtable t1(id int, value int) partitioned by(ds string);
createtable t2(id int, value int) partitioned by(ds string);
createtable t3(c1 int, c2 int, c3 int);
--数据装载,t1表
insert overwrite table t1 partition(ds='20220120')select'1','2022';
insert overwrite table t1 partition(ds='20220121')select'2','2022';
insert overwrite table t1 partition(ds='20220122')select'2','2022';

--数据装载,t2表
insert overwrite table t2 partition(ds='20220120')select'1','120';

当我们执行如下的SQL查询时,会返回什么数据呢?

SELECT*
FROM t1
LEFT JOIN t2
ON t1.id= t2.id
AND t1.ds='20220120'
;

结果1:

1202220220120112020220120

结果2:

1202220220120112020220120
2202220220121NULLNULLNULL
1202220220122NULLNULLNULL

相信对于很多初学者,甚至是一个有开发经验的人来说,会认为结果1是正确的返回结果。其实结果1的并不是正确的结果,真正的返回值是结果2.

是不是跟预期的结果不一致呢?很多初学者会认为上述查询SQL中AND t1.ds = ‘20220120’会进行谓词下推,从而得到结果2。其实,SQL本身的语义不是这样的,如果需要获取结果1的数据,正确的查询方式是下面这样:

--方式1:
SELECT*
FROM t1
LEFT OUTER JOIN t2
ON t1.id= t2.id
WHERE t1.ds='20220120'
;
--方式2:

SELECT*
FROM(
SELECT*
FROM t1
WHERE ds ='20220120'
) t1
LEFT OUTER JOIN t2
ON t1.id= t2.id
;

细心的你看出差异了吗?重点是在WHERE t1.ds = ‘20220120’过滤条件上,最上面的查询方式是ON t1.ds = ‘20220120’,所以按照LEFT JOIN的语义,如果没有过滤条件,那么左表的数据应该全部返回,右表匹配不上则补null。

执行计划

我们先来看看没有谓词下推的查询SQL的执行计划

正常LEFT JOIN

查看执行计划

EXPLAIN
SELECT*
FROM t1
LEFT JOIN t2
ON t1.id= t2.id
AND t1.ds='20220120'
;

执行计划结果

hive> EXPLAIN
>SELECT*
>FROM t1
> LEFT JOIN t2
>ON t1.id= t2.id
>AND t1.ds='20220120'
>;
OK
STAGE DEPENDENCIES:
Stage-4is a root stage
Stage-3 depends on stages: Stage-4
Stage-0 depends on stages: Stage-3

STAGE PLANS:
Stage: Stage-4
Map Reduce Local Work
Alias -> Map Local Tables:
$hdt$_1:t2
Fetch Operator
limit:-1
Alias -> Map Local Operator Tree:
$hdt$_1:t2
TableScan
alias: t2
Statistics: Num rows:1 Data size:5 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: id (type:int), value (type:int), ds (type: string)
outputColumnNames: _col0, _col1, _col2
Statistics: Num rows:1 Data size:5 Basic stats: COMPLETE Column stats: NONE
HashTable Sink Operator
filter predicates:
0{(_col2 ='20220120')}
1
keys:
0 _col0 (type:int)
1 _col0 (type:int)

Stage: Stage-3
Map Reduce
Map Operator Tree:
TableScan
alias: t1
Statistics: Num rows:3 Data size:18 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: id (type:int), value (type:int), ds (type: string)
outputColumnNames: _col0, _col1, _col2
Statistics: Num rows:3 Data size:18 Basic stats: COMPLETE Column stats: NONE
Map Join Operator
condition map:
Left Outer Join0 to 1
filter predicates:
0{(_col2 ='20220120')}
1
keys:
0 _col0 (type:int)
1 _col0 (type:int)
outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5
Statistics: Num rows:3 Data size:19 Basic stats: COMPLETE Column stats: NONE
File Output Operator
compressed:false
Statistics: Num rows:3 Data size:19 Basic stats: COMPLETE Column stats: NONE
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
Local Work:
Map Reduce Local Work

Stage: Stage-0
Fetch Operator
limit:-1
Processor Tree:
ListSink

从上面的执行计划可以看出:总共有3个stage,

STAGE DEPENDENCIES: Stage-4is a root stage Stage-3 depends on stages: Stage-4 Stage-0 depends on stages: Stage-3

其中stage4是map任务读取t2表,将t2表加载成HashTable,用于map端join。t2表数据量为1行。

Select Operator expressions: id (type:int), value (type:int), ds (type: string) outputColumnNames: _col0, _col1, _col2 Statistics: Num rows:1 Data size:5 Basic stats: COMPLETE Column stats: NONE HashTable Sink Operator

stage3是map任务读取t1表数据并执行map端join。t1表数量为3行,可见并没有进行过滤操作。

 Map Operator Tree:
TableScan
alias: t1
Statistics: Num rows:3 Data size:18 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: id (type:int), value (type:int), ds (type: string)
outputColumnNames: _col0, _col1, _col2
Statistics: Num rows:3 Data size:18 Basic stats: COMPLETE Column stats: NONE

Stage-0进行结果输出,最终并未执行过滤操作。

Stage: Stage-0 Fetch Operator limit:-1 Processor Tree: ListSink

谓词下推的LEFT JOIN

  • 查看执行计划
EXPLAIN
SELECT*
FROM t1
LEFT OUTER JOIN t2
ON t1.id= t2.id
WHERE t1.ds='20220120'
;

执行计划结果

STAGE DEPENDENCIES:
Stage-4is a root stage
Stage-3 depends on stages: Stage-4
Stage-0 depends on stages: Stage-3

STAGE PLANS:
Stage: Stage-4
Map Reduce Local Work
Alias -> Map Local Tables:
$hdt$_1:t2
Fetch Operator
limit:-1
Alias -> Map Local Operator Tree:
$hdt$_1:t2
TableScan
alias: t2
Statistics: Num rows:1 Data size:5 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: id (type:int), value (type:int), ds (type: string)
outputColumnNames: _col0, _col1, _col2
Statistics: Num rows:1 Data size:5 Basic stats: COMPLETE Column stats: NONE
HashTable Sink Operator
keys:
0 _col0 (type:int)
1 _col0 (type:int)

Stage: Stage-3
Map Reduce
Map Operator Tree:
TableScan
alias: t1
Statistics: Num rows:1 Data size:6 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: id (type:int), value (type:int)
outputColumnNames: _col0, _col1
Statistics: Num rows:1 Data size:6 Basic stats: COMPLETE Column stats: NONE
Map Join Operator
condition map:
Left Outer Join0 to 1
keys:
0 _col0 (type:int)
1 _col0 (type:int)
outputColumnNames: _col0, _col1, _col3, _col4, _col5
Statistics: Num rows:1 Data size:6 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: _col0 (type:int), _col1 (type:int),'20220120'(type: string), _col3 (type:int), _col4 (type:int), _col5 (type: string)
outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5
Statistics: Num rows:1 Data size:6 Basic stats: COMPLETE Column stats: NONE
File Output Operator
compressed:false
Statistics: Num rows:1 Data size:6 Basic stats: COMPLETE Column stats: NONE
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
Local Work:
Map Reduce Local Work

Stage: Stage-0
Fetch Operator
limit:-1
Processor Tree:
ListSink

从上面的执行计划可以看出:总共有3个stage,

STAGE DEPENDENCIES: Stage-4is a root stage Stage-3 depends on stages: Stage-4 Stage-0 depends on stages: Stage-3

其中stage4是map任务读取t2表,将t2表加载成HashTable,用于map端join。t2表数据量为1行。

 TableScan
alias: t2
Statistics: Num rows:1 Data size:5 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: id (type:int), value (type:int), ds (type: string)
outputColumnNames: _col0, _col1, _col2
Statistics: Num rows:1 Data size:5 Basic stats: COMPLETE Column stats: NONE
HashTable Sink Operator

stage3是map任务读取t1表数据并执行map端join。t1表数量为1行,执行了过滤操作。

TableScan
alias: t1
Statistics: Num rows:1 Data size:6 Basic stats: COMPLETE Column stats: NONE
Select Operator
expressions: id (type:int), value (type:int)
outputColumnNames: _col0, _col1
Statistics: Num rows:1 Data size:6 Basic stats: COMPLETE Column stats: NONE
Map Join Operator
condition map:
Left Outer Join0 to 1
keys:
0 _col0 (type:int)
1 _col0 (type:int)
outputColumnNames: _col0, _col1, _col3, _col4, _col5
Statistics: Num rows:1 Data size:6 Basic stats: COMPLETE Column stats: NONE

Stage-0进行结果输出,最终并未执行过操作。

Stage: Stage-0 Fetch Operator limit:-1 Processor Tree: ListSink

总结本文主要结合具体的使用示例,对HiveSQL的LEFT JOIN操作进行了详细解释。主要包括两种比较常见的LEFT JOIN方式,一种是正常的LEFT JOIN,也就是只包含ON条件,这种情况没有过滤操作,即左表的数据会全部返回。另一种方式是有谓词下推,即关联的时候使用了WHERE条件,这个时候会会对数据进行过滤。所以在写SQL的时候,尤其需要注意这些细节问题,以免出现意想不到的错误结果。

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/230159.html<

(0)
管理的头像管理
上一篇2025-04-19 02:42
下一篇 2025-04-19 02:44

相关推荐

  • 服务器防火墙硬件和软件哪个效果更好,怎么选

    在服务器防火墙的选型中,硬件防火墙与软件防火墙并非非此即彼,而是互补关系,对于追求高安全等级与稳定性的生产环境,采用硬件防火墙做网络层隔离,配合软件防火墙做主机层加固,是当前公认效果最好的组合方案,硬件防火墙与软件防火墙的核心差异性能与资源占用硬件防火墙依托专用ASIC芯片或FPGA处理数据包,转发延迟通常在微……

    2026-07-26
    0
  • 站群服务器做GEO的核心逻辑是什么?,怎么做

    站群服务器做SEO的核心逻辑,是通过独立IP和资源隔离,彻底切断站点间的关联性,让搜索引擎对每个网站进行独立评估,从而降低连带风险并提升整体排名效率,站群服务器的核心价值:独立性与隔离性IP独立性:为什么是命门搜索引擎在评估网站时,会记录IP地址,如果多个站点共享同一个IP,它们之间很容易被判定为同一主体控制……

    2026-07-26
    0
  • 弹性云服务器到底是什么意思怎么收费,多少钱一个月

    弹性云服务器(Elastic Cloud Server,ECS)是一种可随时调整计算资源的云服务器,收费方式以按需付费和包年包月为主,用户只需为实际使用的资源买单,什么是弹性云服务器弹性云服务器本质上是一台运行在云端、配置可以灵活调整的虚拟机,它不像物理服务器那样固定规格,你可以在业务高峰期快速增加CPU、内存……

    2026-07-26
    0
  • 黑洞解封到底是什么意思,需要多久才能恢复

    黑洞解封是指将被黑洞路由策略屏蔽的IP地址恢复正常通信的过程,恢复时间通常取决于攻击流量是否彻底停止,多数情况下在攻击停止后10分钟到24小时内自动解除,用户也可通过联系服务商手动加速解封,黑洞解封到底是什么用拟人化的方式理解,黑洞就是网络世界的“强制隔离区”,当某个IP地址遭遇大量异常流量,比如DDoS攻击……

    2026-07-26
    0
  • 站群服务器IP段怎么选最安全,有哪些注意事项

    选择站群服务器IP段的安全核心在于IP地址的独立性、机房的路由策略以及服务商的合规资质,一个可靠的IP段必须来自持牌自营机房,具备独立C段和清洗能力,才能避免被关联风险,为什么IP段选择决定站群安全搜索引擎对IP关联的识别算法近年来越来越精细,同一C段或广播域的IP,爬虫通过反向DNS、路由跳数等特征很容易判断……

    2026-07-26
    0

发表回复

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