SQL中的内连接(inner join)、外连接(left|right join、full join)以及on关键字中涉及分区筛选、null解释

一、简介

本篇幅主要介绍了:

  1. SQL中内连接(inner join)、外连接(left join、right join、full join)的机制;
  2. 连接关键字on上涉及表分区筛选的物理执行及引擎优化;
  3. null在表关联时的情况与执行;

内容适用于常见大数据计算引擎,诸如hive、tez、sparksql、presto(trino)等。考虑到后续引擎版本迭代,具体执行以物理执行计划为准,查看执行计划只需再SQL最前方加上explain关键字即可,比如:explain select t1.id,t2.id as id2 from tablename1 t1 join tablename2 t2 on t1.id=t2.id

阅读者适用于SQL入门还没弃坑的同学。

二、有关sql中null的解读

1. 空这个概念

sql中,人们称之为,一般有三种解释:

  1. 空字符串,''
  2. 不合理,不存在,比如小孩的年龄,如果xx用户都没有小孩,那就不存在这个概念了
  3. 不确定,未知。sql中的null一般做该中解释,未知意味着null与null以及任何只与null的判断都是返回null;sql中的null只能用is null才能返回true

比如:select 5>null;
在这里插入图片描述
select null=null也是返回null
在这里插入图片描述
select null is null返回true
在这里插入图片描述

2. 当null出现在逻辑and和or条件里

and 两边都是true才返回true;
select 1>null and true返回null
在这里插入图片描述

or 两边只要有一边是true就返回true;
select 1>null or true 返回true
在这里插入图片描述

3. and和or的优先级

where field_name1 is not null and field_name2>100 or field_name3 is not null and field_name4>0 or field_name5 is not null

这段sql判断逻辑等于:where (field_name1 is not null and field_name2>100) or (field_name3 is not null and field_name4>0) or field_name5 is not null

先and前后判断,最后剩下几个or的或关系

为提升可读性,当涉及多个and,or条件判断时,尽量用括号括起来(如上);

如果条件放在join的on里边作用一样;

select t1.id,t2.id,t2.field_name2 
from tablename1 t1 
join tablename2 t2 
on 1=null and t1.id=t2.id and t1.dt='20241109' and t2.dt='20241109' and t1.id>100 or t2.id<300

以上sql返回t2.id<300的笛卡尔交集

三、连接机制介绍

首先理解内连接和外连接的机制,然后再看on关键字的作用;on关键字的条件只是判断在什么情况下两个表的记录行会产生关联行为;

有表:tablename1tablename2,两个表都是分区表,且两个表的分区字段名都是dt

1. 内连接:inner join

取交集

样例sql:

select t1.id,t2.id,t2.field_name2 
from tablename1 t1 
join tablename2 t2 
on t1.id=t2.id and t1.dt='20241109' and t2.dt='20241109' and t1.id>100

等于(这个t1.id>100是在join之前得tablescan中filter筛选的):
sql1:

select t1.id,t2.id,t2.field_name2 
from tablename1 t1 
join tablename2 t2 
on t1.id=t2.id 
where  t1.dt='20241109' and t2.dt='20241109' and t1.id>100 and t2.id is not null

等于sql2:

select t1.id,t2.id,t2.field_name2 
from (select id from tablename1 where dt='20241109' and t1.id>100) t1 
join (select id,field_name2 from tablename2 where dt='20241109' and is not null) t2 
on t1.id=t2.id

需要注意的是,有一种sql写法,表里没有join,实际也是按inner join走的,比如下面这段sql:

select t1.appid,t1.target,t1.sq,t2.product_type
from ads_mg_core_target_value t1 ,dim_game_info t2 
where t1.appid=t2.appid

我们打印下执行计划:

explain select t1.appid,t1.target,t1.sq,t2.product_type
from ads_mg_core_target_value t1 ,dim_game_info t2 
where t1.appid=t2.appid

在这里插入图片描述
我这里装的是单机hive,且表体量都很小,所以打印的执行计划最后走的是mapjoin

我们把自动mapjoin给关掉,再看下:set hive.auto.convert.join=false;

在这里插入图片描述
这时候显示的是reduce join了

以上三个sql案例,两个表都只读了20241109一个分区的数据,且t1.id>100都是在读分区map时扫描过滤的(引擎优化)

因为null与任何的判断最终都是返回null(除了isnull判断),所以当sql不涉及isnull判断时,对于on量表关联的字段,引擎会做优化,在tablescan表扫描时将null值给剔掉,故inner join不存在null的倾斜(在map时全剔掉了)

在这里插入图片描述

2. 左右连接:left join | right join

left join 跟right join的机制大致等同,一个保留左表全部数据(left join),一个保留右表全部数据(right join)

我们还是以上面的sql为案例,改成left join
sql-1

select t1.id,t2.id,t2.field_name2 
from tablename1 t1 
left join tablename2 t2 
on t1.id=t2.id and t1.dt='20241109' and t2.dt='20241109' and t1.id>100

这段sql如果t1表全量数据体量很大,那就是灾难了,tablename1全表扫描,因为left join保留左表全部数据。大概率是写sql的人sql写错了;tablename2表只读了一个分区;对于not (t1.dt='20241109' and t1.id>100)部门,on没有符合的条件,t2.field_name2全都是null;

不等于
sql-2

select t1.id,t2.id,t2.field_name2 
from tablename1 t1 
left join tablename2 t2 
on t1.id=t2.id 
where t1.dt='20241109' and t2.dt='20241109' and t1.id>100

等于sql-3:

select t1.id,t2.id,t2.field_name2 
from tablename1 t1 
left join tablename2 t2 
on t1.id=t2.id and t1.dt='20241109' and  t1.id>100
where t2.dt='20241109'

等于sql-4:

select t1.id,t2.id,t2.field_name2 
from tablename1 t1 
join (select * from tablename2 where dt='20241109' where id is not null) t2 
on t1.id=t2.id and t1.dt='20241109' and  t1.id>100

3. 全连接:full join

全量接,左右会保留左右两边表的所有记录行,对于on关联不上的,被关联表的字段返回null。
sql-1

select t1.id,t2.id,t2.field_name2 
from tablename1 t1 
full join tablename2 t2 
on t1.id=t2.id and t1.dt='20241109' and t2.dt='20241109' and t1.id>100

这个表最后就是tablename1和tablename2两个表都全表扫描,只有当on条件成立是才会映射被关联表字段,其他关联不上的,被关联表该字段都是null;

如果要筛选分区及条件后再用id full join,只能先用子查询改写再join

select  t1.id,t2.id,t2.field_name2 
from (select t1.id from tablename1 where id>100 and dt='20241109') t1 
full join (select id,field_name2 from tablename2 where dt='20241109') t2 
on t1.id=t2.id 

现在有两个表:
在这里插入图片描述
两个表用id字段full join,也就是t1 full join t2 on t1.id=t2.id

那么结果返回几条呢?

因为null与任何非isnull判断都是返回null,full join保留左右表全部数据,所以该段sql一共返回6行数据,测试sql:

select t1.id as t1_id,t2.id as t2_id 
from 
(select null as idunion all select 1 as id union all select 2 as id 
) t1 
full join 
(select 2 as idunion all select null as id union all select null as id union all select 4 as id 
) t2
on t1.id=t2.id 
order by t1.id desc,t2.id desc 

实际返回如下:

在这里插入图片描述

4. left semi join

这是一种特殊的join,sql中in/exists的实现。相比普通inner join,匹配到一条数据就无须再尝试匹配其他数据了。inner join遇到重复会发散;left semi join只会返回左表的部分(仅on的key参与计算);语法支持的情况,也可以用in去改写。具体看执行计划。

5. 多表关联

当存在多表关联时,一般的执行顺序是从左往右走,比如:

tablename1 t1 
left join tablename2 t2
on t1.id=t2.id 
join tablenamme3 t3
on t1.id2=t3.id2

先t1跟t2 left join,结果再跟t3 join;

有的引擎会基于成本优化,调整join顺序,以上sql可能物理执行时这样的(因为两者结果是等同的,如果t2表很小,t3表很大,可能会做出这种优化,具体看物理执行):

tablename1 t1 
join tablenamme3 t3
on t1.id2=t3.id2
left join tablename2 t2
on t1.id=t2.id 

也会有一种情况,如果多表关联on的关联条件是相同的,比如(都是id):

tablename1 t1 
left join tablename2 t2
on t1.id=t2.id 
join tablenamme3 t3
on t1.id=t3.id

看起来有两个join,实际在大数据中,只跑了一段mr,map时读取三个表的数据,reduce左两个join的关联再返回。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/58815.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CMS垃圾回收流程的理解

初始标记&#xff1a;STW&#xff0c;标记处GC roots能直接关联到的对象速度很快 并发标记&#xff1a;垃圾回收线程和工作线程同时工作&#xff0c;遍历整个对象图&#xff0c;标记出可达对象 重新标记&#xff1a;STW&#xff0c;重新标记出并发标记阶段新产生的垃圾对象。&a…

Vite环境下uniapp Vue 3项目添加和使用环境变量的完整指南

一、引言 在uniapp项目中&#xff0c;合理配置环境变量对于提高开发效率和保障项目安全至关重要。Vite作为新一代的前端构建工具&#xff0c;为环境变量的管理提供了简洁而强大的支持。下面&#xff0c;我们将一步步学习如何在Vite环境下为uniapp Vue 3项目添加和使用环境变量…

Flutter鸿蒙next 中的 Drawer 导航栏

在 Flutter 中&#xff0c;Drawer 是一个非常常见的侧边栏导航组件。通过点击菜单按钮或滑动屏幕&#xff0c;我们可以显示一个滑动抽屉&#xff0c;它通常用于展示应用程序中的重要导航项。实现一个 Drawer 导航栏不仅能提升应用的用户体验&#xff0c;还能有效地管理多个页面…

机器学习(一)——基本概念、模型的评估与选择

目录 1 关于2 概念2.1 基础概念2.2 学习过程2.3 预测与评估2.4 标记与分类2.4.1 标记2.4.2 分类 2.5 回归分析2.6 聚类分析2.7 学习类型2.8 泛化能力2.9 统计学概念 3 模型评估与选择3.1 经验误差与过拟合3.2 评估方法3.2.1 留出法3.2.2 交叉验证法3.2.3 自助法3.2.4 调参与最终…

leetcode02 --- 合并两个有序链表

题目 . - 力扣&#xff08;LeetCode&#xff09; 合并两个有序链表 代码 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, L…

公开仓库改私有再配置公钥后Git拉取仍需要输入用户名的问题

问题描述&#xff1a;git拉取私有仓库需要输入用户名和密码 我之前写了一个脚本用来定时自动拉取远程仓库更新本地仓库&#xff0c;后来将这个远程仓库改成私有后执行脚本就会需要输入用户名和密码。 [rootLH2020 ~]# ./sync_repo.sh 正在从远程仓库拉取最新更改… Username f…

ssm060基于SSM的高校共享单车管理系统的设计与实现+vue(论文+源码)_kaic

设计题目&#xff1a;高校共享单车管理系统的设计与实现 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0…

聚观早报 | 比亚迪腾势D9登陆泰国;苹果 iOS 18.2 将发布

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 11月5日消息 比亚迪腾势D9登陆泰国 苹果 iOS 18.2 将发布 真我GT7 Pro防尘防水细节 小米15 Ultra最快明年登场 …

三菱QD77MS定位模块速度更改功能

速度更改功能” 是以任意时机将控制中的速度更改为新指定的速度的功能。更改后的速度直接设置到缓冲存储器中&#xff0c;并根据速度更改指令([cd.15速度更改请求)或者外部指令信号执行速度更改。 但是&#xff0c;机械原点复位的情况下&#xff0c;检测出近点狗 ON 并开始向蠕…

2024系统分析师---微服务架构(淘宝押题)

2020年6月,我单位联合 xxx、xxx有限公司开发了省 xxx 综合应用管理平台,作为公司核心技术骨干,我担任了系统架构师的职务,主要负责xxx应用系统架构体系设计及核心组件的开发工作。该系统按照省机关业务类型划分,依次包含基础功能支撑板块、平台资源管理板块、煤炭能源板块…

读多写少业务中,MySQL如何优化数据查询方案?

小熊学Java​站点:https://www.javaxiaobear.cn 编程资料合集:https://pqgmzk7qbdv.feishu.cn/base/QXq2bY5OQaZiDksJfZMc30w5nNb?from=from_copylink 看一看当面试官提及“在读多写少的网络环境下,MySQL 如何优化数据查询方案”时,你要从哪些角度出发回答问题??? 案例…

flink 内存配置(二):设置TaskManager内存

flink 内存配置&#xff08;一&#xff09;&#xff1a;设置Flink进程内存 flink 内存配置&#xff08;二&#xff09;&#xff1a;设置TaskManager内存 flink 内存配置&#xff08;三&#xff09;&#xff1a;设置JobManager内存 flink 内存配置&#xff08;四&#xff09;…

js 好用的字符操作方法

序&#xff1a;突然感觉有些方法常见有时也用&#xff0c;但怕有时不记得&#xff0c;顺便记录一下&#xff01; 一、获取类方法 let str "Hello,你们好!" console.log(str.charAt(6)) // 你 console.log(str.charAt(12)) // (空字符串)console.log(st…

Flutter鸿蒙next中的按钮封装:自定义样式与交互

在Flutter应用开发中&#xff0c;按钮是用户界面中不可或缺的组件之一。它不仅用于触发事件&#xff0c;还可以作为视觉元素增强用户体验。Flutter提供了多种按钮组件&#xff0c;如ElevatedButton、TextButton、OutlinedButton等&#xff0c;但有时这些预制的按钮样式无法满足…

线段树专题(1)

线段树 线段树可维护的信息类型 线段树可以维护的信息类型&#xff0c;父范围上的某个信息&#xff0c;可以用O(1)的时间&#xff0c;从子范围的信息加工得到&#xff0c;例如求某个范围的最大最小值&#xff0c;给某个范围每个位置加相同的数字&#xff0c;进行求和。 0到2范…

Neo4j数据库清理指南:如何安全地删除所有节点和索引

Neo4j数据库清理指南&#xff1a;如何安全地删除所有节点和索引 1. 基础知识2. 安全注意事项3. 清理数据库的步骤3.1 删除所有节点和关系3.2 删除所有索引和约束 4. 在Python中执行这些操作5. 常见问题解答6. 最佳实践建议结语 在使用Neo4j图数据库进行开发时&#xff0c;我们有…

NoETL自动化指标平台为数据分析提质增效,驱动业务决策

直觉判断往往来源于多年的经验和专业知识&#xff0c;能够在复杂和不确定的环境中快速做出决策反应。但这种方式普遍存在主观偏见&#xff0c;缺乏合理的科学依据&#xff0c;无法全面、客观、精准地评估和识别市场趋势与用户需求&#xff0c;从而造成决策失误&#xff0c;给业…

软考高级架构 - 8.1 - 系统质量属性与架构评估 - 超详细讲解+精简总结

第8章 系统质量属性与架构评估 软件系统属性包括功能属性和质量属性&#xff0c;而软件架构重点关注质量属性。 8.1 软件系统质量属性 8.1.1 概述 软件系统的质量反映了其与需求的一致性&#xff0c;即&#xff1a;软件系统的质量高低取决于它是否能满足用户提出的需求&#…

Windows系统使用OpenSSL生成自签名证书

Nginx服务器添加SSL证书。 要在Windows系统的Nginx Web服务器上使用OpenSSL生成证书&#xff0c;并确保该证书能在局域网内被计算机信任&#xff0c;你可以按照以下详细步骤进行操作&#xff1a; 一、生成证书 下载并安装OpenSSL&#xff1a; 从OpenSSL的官方网站下载适用于Wi…

Jmeter常见的几种报错及解决方案

在性能测试的过程中&#xff0c;使用JMeter进行负载测试是一项常见而重要的任务。然而&#xff0c;测试中常常会遇到各种报错&#xff0c;这些问题可能会影响测试结果的准确性。了解这些错误的原因及解决方案&#xff0c;是每位测试工程师必备的技能 进行Jmeter项目练习的时候…