百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

多表关联查询过滤条件写在on与where后的区别

wptr33 2024-12-26 17:07 34 浏览

SQL优化过程中,发现开发人员在写多表关联查询的时候,对于谓词过滤条件的写法很随意,写在on后面与where后面的情况均有,这可能会导致没有理解清楚其真正的含义而无法得到期望的结果。

多表关联连接方式有inner join、left join、right join、full join四种,下面通过实验来说明不同连接方式谓词放在on与where后的效果与影响。

初始化测试数据

create table t1(id number(10),name varchar2(30),status varchar2(2));
create table t2(id number(10),mobile varchar2(30));
insert into t1 values(1,'a','1');
insert into t1 values(2,'b','1');
insert into t1 values(3,'c','1');
insert into t1 values(4,'d','1');
insert into t1 values(5,'e','1');
insert into t1 values(6,'f','0');
insert into t1 values(7,'g','0');
insert into t1 values(8,'h','0');
insert into t1 values(9,'i','0');
insert into t1 values(10,'j','0');
insert into t2 values(1,'12345');
insert into t2 values(2,'23456');
insert into t2 values(3,'34567');
insert into t2 values(6,'67890');
insert into t2 values(7,'78901');

1.Inner join

SQL>select * from t1 inner join t2 on t1.id=t2.id and t1.status=‘1’;

   ID NAME                          ST         ID MOBILE
     1 a                            1           1 12345
     2 b                            1           2 23456
     3 c                            1           3 34567

SQL> select * from t1 inner join t2 on t1.id=t2.id where t1.status=‘1’;

   ID NAME                         ST         ID MOBILE
     1 a                            1           1 12345     
     2 b                            1           2 23456
     3 c                            1           3 34567

我们发现谓词t1.status=’1’放在on后与where后结果一样,它们的执行计划相同,说明CBO对这两种情况做了相同处理。
执行计划如下图所示:

Inner join时谓词不管放在哪个位置,CBO都先对t1表过滤,再与t2表关联。

2.left join

(1)左右表谓词过滤都放在on后面:
SQL> select * from t1 left join t2 on t1.id=t2.id and t1.status=‘1’ and t2.id<3;

  ID NAME                           ST         ID MOBILE
      1 a                            1           1 12345
      2 b                            1           2 23456
      3 c                            1    
      8 h                            0    
      5 e                            1    
      9 i                            0   
     10 j                            0    
      7 g                            0    
      6 f                            0    
      4 d                            1

执行计划如下:

从执行计划可以看出,t1.status=’1’放在on后面,t1表并没有对谓词status进行过滤,结果集显示t1的全表数据。这是由left join的特性决定的,左表会显示全部数据。t2.id<3是先对t2表进行过滤再进行连接,而t1.status=’1’是作为连接条件存在,对连接时产生的笛卡尔积数据做连接过滤。
(2)左右表谓词过滤都放在where后面:
SQL>select * from t1 left join t2 on t1.id=t2.id where t1.status=‘1’ and t2.id<3;

   ID NAME                           ST         ID MOBILE
       1 a                            1           1 12345
       2 b                            1           2 23456

从执行计划可以看出,谓词放在where后面,是先对表进行过滤,然后再对过滤后的数据进行连接。而且我们发现t1表上自动加上了id<3的过滤条件,这是因为有t1.id=t2.id等值连接,如果t1表上id列有索引,性能就能看出差别来了。注意连接方式变成了hash join,这是因为右表的谓词过滤条件写在where后面,CBO会把左连接等价为内连接。

(3)右表的谓词写在on后面,左表的谓词写在where后面:
SQL>select * from t1 left join t2 on t1.id=t2.id and t2.id<3
where t1.status=‘1’; 2

  ID NAME                          ST         ID MOBILE
      1 a                            1           1 12345
      2 b                            1           2 23456
      5 e                            1
      4 d                            1
      3 c                            1

当把对右表的过滤写在on后面,先对两表进行过滤,再进行left join,显示结果集与写在where后面是不同的,连接方式还是左外连接,显示t1过滤后的全部数据。
(4)右表的谓词写在where后面,左表的谓词写在on后面:
SQL> select * from t1 left join t2 on t1.id=t2.id and t1.status=‘1’ where t2.id<7;

   ID NAME                       ST         ID MOBILE
     1 a                            1           1 12345
     2 b                            1           2 23456
     3 c                            1           3 34567

从执行计划看这种情况左连接转换为内连接,左表的谓词条件写在哪个位置都一样。而且因为t2表过滤后数据比t1表少,CBO把t2表当成了驱动表。
接下来我们再看一个语句:
SQL> select * from t1 left join t2 on t1.id=t2.id and t1.status=‘1’
where t1.status=‘0’ ;

  ID NAME                        ST         ID MOBILE
    8 h                            0
    6 f                            0
    9 i                            0
  10 j                            0
   7 g                            0

从执行计划看出,虽然t2表返回0行,步骤3上的filter条件肯定不成立,但有逻辑读消耗,所以推断它依然进行了全表扫描,所以这种语句对t2表的扫描是对资源的一种浪费,没有意义。或许你会觉得谁会这么无聊写这种SQL,但是在开发过程中,SQL语句经常是各种过滤条件组合经过拼接而成,因为返回结果是对的,他们意识不到会出现这种问题,在此说明此种情况主要是想说明一件事:不要总想着用一个语句来解决所有的功能需求,适当的拆分对性能的提升是很有必要的。

3.right join

右连接与左连接是相似的,只不过是右表显示全部数据,写在on后面谓词过滤对右表不起作用,在此不再举例说明。

4.full join

全连接在应用中似乎很少碰到,但是存在即合理,只是自己没有遇到而已。
(1)两个表的谓词都放在on的后面:

这种情况不会先对两个表过滤,而是作为连接条件过滤,符合连接就匹配上,不符合的就把左右两表的数据都显示出来,另一表的字段以空显示。
(2)两个表的谓词都放在where后面:

这种情况CBO将其转换为内连接,先过滤再关联。
(3)左表谓词放在on后面,右表放在where后面:

这种情况转换为右外连接,但是也是先对两表过滤后再关联。
(4)左表谓词放在where后面,右表放在on后面:

这种情况转换为左外连接,也是先对两表过滤后再关联。

总结

1.对于内连接inner join,两个表的谓词条件放在on与where后面相同。
2.对于left join:
左表谓词放在on后不会对左表数据进行过滤,依然显示左表全部数据,放在where后面才会对左表进行过滤
右表谓词不管放在on后还是where后都会对右表先过滤再连接,但是放在where后left join会转换为inner join。
3.对于外连接,谓词条件放的位置不同,结果集也不同,可以根据自己的需求斟酌使用。

墨天轮原文链接:https://www.modb.pro/db/101411(复制链接至浏览器或点击多表关联查询过滤条件写在on与where后的区别 - 墨天轮查看)

关于作者

于志君,云和恩墨技术顾问,Oracle 12c OCM。拥有OCM、OBCA证书,曾在某大型国企做过多年数据库运维工作,现驻场于某银行,专门从事SQL性能优化工作,热衷于运维故障处理、备份恢复、升级迁移、性能优化的学习与分享。

相关推荐

开发者必看的八大Material Design开源项目

MaterialDesign是介于拟物和扁平之间的一种设计风格,自从它发布以来,便引起了很多开发者的关注,在这里小编介绍在Android开发者当中里最受青睐的八个MaterialDesign开源项...

另类插这么可爱,一定是…(另类t恤)

IT之家(www.ithome.com):另类插图:这么可爱,一定是…OSXMavericks和Yosemite打破了苹果对Mac操作系统传统的命名方式,使用加州的某些标志性景点来替换猫...

Android常用ADB命令(安卓adb工具是什么)

杀死应用①根据包名获取APP的PIDadbshellps|grep应用包名②执行kill命令...

微软Mac版PowerPoint测试Reading Order Pane功能

IT之家5月20日消息,微软公司昨日(5月19日)发布博文,邀请Microsoft365Insiders成员,测试macOS新版PowerPoint演示文稿应用,重点引入...

Visual Studio跨平台开发实战(4):Xamarin Android控制项介绍

前言不同于iOS,Xamarin在VisualStudio中针对Android,可以直接设计使用者界面.在本篇教学文章中,笔者会针对Android的专案目录结构以及基本控制项进行介绍,包...

用云存储30分钟快速搭建APP,你信吗?

背景不管你承认与否,移动互联的时代已经到来,这是一个移动互联的时代,手机已经是当今世界上引领潮流的趋势,大型的全球化企业和中小企业都把APP程序开发纳入到他们的企业发展策略当中。但随着手机APP上传的...

谷歌P图神器来了!不用学不用教,输入一句话,分分钟给结果

Pine发自凹非寺量子位|公众号QbitAI当你拍照片时,“模特不好好配合”怎么办?...

iOS文本编辑控件UITextField和UITextVie

记录一个菜鸟的IOS学习之旅,如能帮助正在学习的你,亦枫不胜荣幸;如路过的大神如指教几句,亦枫感激涕淋!细心的朋友可能已经注意到了,IOS学习之旅系列教程在本篇公众号的文章中,封面已经换成美女图片了,...

Android入门图文教程集锦(android 入门教程)

Android入门视频教程集锦AndroidStudio错误gradientandroid:endXattributenotfound...

如何使用Android自定义复合视图(如何使用android自定义复合视图)

在最近的一个客户应用中,我遇到了一个需求,根据选定的值来生成指定数量的编辑框字段,这样用户可以输入人物信息。最初我的想法是把这些逻辑放到Fragment中,只是根据选中值的变化来向线性布局容器中增加编...

原生安卓开发app的框架frida常用关键代码定位

前言有时候可能会对APP进行字符串加密等操作,这样的话你的变量名等一些都被混淆了,看代码就可能无从下手...

教程10 | 三分钟搞定一个智能输入法程序

一案例描述1、考核知识点网格布局线性布局样式和主题Toast2、练习目标掌握网格布局的使用掌握Toast的使用掌握线性布局的使用...

(Android 8.1) 功能与新特性(android的功能)

和你一起终身学习,这里是程序员AndroidAndroid8.1(API级别27)为用户和开发人员引入了各种新特性和功能。本文档重点介绍了开发人员的新功能。通过本章阅读,您将获取到以下内容:Andr...

怎样设置EditText内部文字被锁定不可删除和修改

在做项目的时候,我曾经遇到过这样的要求,就是跟百度贴吧客户端上的一样,在回复帖子的时候,在EditText中显示回复人的名字,而且这个名字不可以修改和删除,说白了就是不可操作,只能在后面输入内容。在E...

如何阻止 Android 活动启动时 EditText 获得焦点

技术背景在Android开发中,当活动启动时,EditText有时会自动获得焦点并弹出虚拟键盘,这可能不是用户期望的行为。为了提升用户体验,我们需要阻止...