小知识:IN和EXISTS的用法及效率验证
环境: Oracle 19.16 多租户架构
经常会在网上看到有人写exists和in的效率区别,其实在新版本的数据库中,是不存在这个问题的,优化器会自己判断选择最优的执行计划。
为了直观的说明,我在PDB中构造如下测试用例:
vi 1.sql
select count(*) from v$active_session_history;
select count(*) from dba_hist_active_sess_history;
create table T1 as select * from v$active_session_history;
create table T2 as select * from dba_hist_active_sess_history;
构造小表T1,大表T2。
SQL> set timing on
SQL> @1
COUNT(*)
----------
383
Elapsed: 00:00:00.05
COUNT(*)
----------
215636
Elapsed: 00:00:00.95
Table created.
Elapsed: 00:00:00.20
Table created.
Elapsed: 00:00:07.90
网上说,当T1数据量小,而T2数据量非常大时,使用exists的查询效率会高。
验证下,是否事实真是如此?
select /*+ monitor */ * from T1 where exists(select 1 from T2 where T1.sql_id = T2.sql_id) ;
select /*+ monitor */ * from T1 where T1.sql_id in (select T2.sql_id from T2) ;
SQL> select sql_id, sql_text from v$sql where sql_text like '%T2.sql_id%'
SQL_ID SQL_TEXT
------------- ------------------------------------------------------------------------------------------
4xu586p9h0qcq select /*+ monitor */ * from T1 where T1.sql_id in (select T2.sql_id from T2)
3qgrm97t5jgwj select /*+ monitor */ * from T1 where exists(select 1 from T2 where T1.sql_id = T2.sql_id)
使用sqlmon取到两个SQL对应的SQL Monitor Report,对比分析发现:
二者执行计划完全一样,对应Plan Hash Value 1713220790,都走的是Hash Join Semi,执行时间也没差别。
所以这个说法最起码在Oracle 19c的版本中是不存在的,你想怎么写都OK,优化器会帮你做查询转换。
为了进一步验证,构造4个典型SQL,分别使用in和exists的写法:
--SQL1:
select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID, count(*)
from T1
where T1.sql_id in (select T2.sql_id from T2)
group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID
order by 1;
--SQL2:
select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID, count(*)
from T1
where exists (select 1 from T2 where T2.sql_id = T1.sql_id)
group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID
order by 1;
--SQL3:
select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID, count(*)
from T2
where T2.sql_id in (select T1.sql_id from T1)
group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID
order by 1;
--SQL4:
select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID, count(*)
from T2
where exists (select 1 from T1 where T1.sql_id = T2.sql_id)
group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID
order by 1;
SQL Monitor的截图就不贴了,直接给大家看下文本格式的执行计划,方便对比和检索:
SQL1:
SQL> select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID, count(*)
2 from T1
3 where T1.sql_id in (select T2.sql_id from T2)
4 group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID
5 order by 1;
SQL_ID SQL_PLAN_HASH_VALUE SQL_PLAN_LINE_ID COUNT(*)
------------- ------------------- ---------------- ----------
3dbzmtf9ahvzt 3238164414 1 1
3kqrku32p6sfn 2977818336 14 1
3zbvwad7h1pgt 2360206614 1 2
3zbvwad7h1pgt 2360206614 6
87gaftwrm2h68 0 1
9wncfacx0nj9h 0 2
9wncfacx0nj9h 3312548573 9
avf5k3k0x0cxn 3746835944 1 1
b13g21mgg8y98 212733457 9 1
b13g21mgg8y98 212733457 12 2
ggh55rhz95kyj 3124993369 8
gug127tbfzjcs 3645025857 0 1
12 rows selected.
Elapsed: 00:00:00.07
SQL> @xplan
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 250w6cua1mfa0, child number 2
-------------------------------------
select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID,
count(*) from T1 where T1.sql_id in (select T2.sql_id from T2) group by
SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID order by 1
Plan hash value: 910330555
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 12 |00:00:00.07 | 16132 | | | |
| 1 | SORT GROUP BY | | 1 | 228 | 12 |00:00:00.07 | 16132 | 2048 | 2048 | 2048 (0)|
|* 2 | HASH JOIN SEMI | | 1 | 228 | 35 |00:00:00.07 | 16132 | 1376K| 1376K| 1604K (0)|
|* 3 | TABLE ACCESS FULL| T1 | 1 | 228 | 228 |00:00:00.01 | 26 | | | |
|* 4 | TABLE ACCESS FULL| T2 | 1 | 177K| 177K|00:00:00.06 | 16106 | | | |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."SQL_ID"="T2"."SQL_ID")
3 - filter("T1"."SQL_ID" IS NOT NULL)
4 - filter("T2"."SQL_ID" IS NOT NULL)
25 rows selected.
Elapsed: 00:00:00.04
SQL2:
SQL> select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID, count(*)
2 from T1
3 where exists (select 1 from T2 where T2.sql_id = T1.sql_id)
4 group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID
5 order by 1;
SQL_ID SQL_PLAN_HASH_VALUE SQL_PLAN_LINE_ID COUNT(*)
------------- ------------------- ---------------- ----------
3dbzmtf9ahvzt 3238164414 1 1
3kqrku32p6sfn 2977818336 14 1
3zbvwad7h1pgt 2360206614 1 2
3zbvwad7h1pgt 2360206614 6
87gaftwrm2h68 0 1
9wncfacx0nj9h 0 2
9wncfacx0nj9h 3312548573 9
avf5k3k0x0cxn 3746835944 1 1
b13g21mgg8y98 212733457 9 1
b13g21mgg8y98 212733457 12 2
ggh55rhz95kyj 3124993369 8
gug127tbfzjcs 3645025857 0 1
12 rows selected.
Elapsed: 00:00:00.06
SQL> @xplan
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID cxn8artthq7p8, child number 0
-------------------------------------
select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID,
count(*) from T1 where exists (select 1 from T2 where T2.sql_id =
T1.sql_id) group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID order
by 1
Plan hash value: 910330555
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 12 |00:00:00.06 | 16132 | | | |
| 1 | SORT GROUP BY | | 1 | 228 | 12 |00:00:00.06 | 16132 | 2048 | 2048 | 2048 (0)|
|* 2 | HASH JOIN SEMI | | 1 | 228 | 35 |00:00:00.06 | 16132 | 1376K| 1376K| 1611K (0)|
|* 3 | TABLE ACCESS FULL| T1 | 1 | 228 | 228 |00:00:00.01 | 26 | | | |
|* 4 | TABLE ACCESS FULL| T2 | 1 | 177K| 177K|00:00:00.05 | 16106 | | | |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T2"."SQL_ID"="T1"."SQL_ID")
3 - filter("T1"."SQL_ID" IS NOT NULL)
4 - filter("T2"."SQL_ID" IS NOT NULL)
26 rows selected.
Elapsed: 00:00:00.03
SQL3:
SQL> select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID, count(*)
2 from T2
3 where T2.sql_id in (select T1.sql_id from T1)
4 group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID
5 order by 1;
SQL_ID SQL_PLAN_HASH_VALUE SQL_PLAN_LINE_ID COUNT(*)
------------- ------------------- ---------------- ----------
3dbzmtf9ahvzt 3238164414 1 1
3kqrku32p6sfn 1774581179 20 2
3kqrku32p6sfn 1774581179 23 2
3kqrku32p6sfn 2977818336 14 2
3zbvwad7h1pgt 2360206614 1
87gaftwrm2h68 1072382624 2 2
9wncfacx0nj9h 3312548573 2
avf5k3k0x0cxn 3746835944 1 1
b13g21mgg8y98 212733457 9 1
b13g21mgg8y98 2612542848 1 2
ggh55rhz95kyj 3124993369 4
gug127tbfzjcs 3645025857 1
12 rows selected.
Elapsed: 00:00:00.09
SQL> @xplan
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 1588n6cc48yv0, child number 0
-------------------------------------
select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID,
count(*) from T2 where T2.sql_id in (select T1.sql_id from T1) group by
SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID order by 1
Plan hash value: 3152222881
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 12 |00:00:00.08 | 16132 | | | |
| 1 | SORT GROUP BY | | 1 | 3684 | 12 |00:00:00.08 | 16132 | 2048 | 2048 | 2048 (0)|
|* 2 | HASH JOIN RIGHT SEMI| | 1 | 3684 | 21 |00:00:00.08 | 16132 | 1651K| 1651K| 1520K (0)|
|* 3 | TABLE ACCESS FULL | T1 | 1 | 228 | 228 |00:00:00.01 | 26 | | | |
|* 4 | TABLE ACCESS FULL | T2 | 1 | 177K| 177K|00:00:00.08 | 16106 | | | |
-------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T2"."SQL_ID"="T1"."SQL_ID")
3 - filter("T1"."SQL_ID" IS NOT NULL)
4 - filter("T2"."SQL_ID" IS NOT NULL)
25 rows selected.
Elapsed: 00:00:00.03
SQL4:
SQL> select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID, count(*)
2 from T2
3 where exists (select 1 from T1 where T1.sql_id = T2.sql_id)
4 group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID
5 order by 1;
SQL_ID SQL_PLAN_HASH_VALUE SQL_PLAN_LINE_ID COUNT(*)
------------- ------------------- ---------------- ----------
3dbzmtf9ahvzt 3238164414 1 1
3kqrku32p6sfn 1774581179 20 2
3kqrku32p6sfn 1774581179 23 2
3kqrku32p6sfn 2977818336 14 2
3zbvwad7h1pgt 2360206614 1
87gaftwrm2h68 1072382624 2 2
9wncfacx0nj9h 3312548573 2
avf5k3k0x0cxn 3746835944 1 1
b13g21mgg8y98 212733457 9 1
b13g21mgg8y98 2612542848 1 2
ggh55rhz95kyj 3124993369 4
gug127tbfzjcs 3645025857 1
12 rows selected.
Elapsed: 00:00:00.09
SQL> @xplan
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 99fkm9p94agcf, child number 0
-------------------------------------
select /*+ monitor */ SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID,
count(*) from T2 where exists (select 1 from T1 where T1.sql_id =
T2.sql_id) group by SQL_ID, SQL_PLAN_HASH_VALUE, SQL_PLAN_LINE_ID order
by 1
Plan hash value: 3152222881
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 12 |00:00:00.09 | 16132 | | | |
| 1 | SORT GROUP BY | | 1 | 3684 | 12 |00:00:00.09 | 16132 | 2048 | 2048 | 2048 (0)|
|* 2 | HASH JOIN RIGHT SEMI| | 1 | 3684 | 21 |00:00:00.09 | 16132 | 1651K| 1651K| 1520K (0)|
|* 3 | TABLE ACCESS FULL | T1 | 1 | 228 | 228 |00:00:00.01 | 26 | | | |
|* 4 | TABLE ACCESS FULL | T2 | 1 | 177K| 177K|00:00:00.08 | 16106 | | | |
-------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."SQL_ID"="T2"."SQL_ID")
3 - filter("T1"."SQL_ID" IS NOT NULL)
4 - filter("T2"."SQL_ID" IS NOT NULL)
26 rows selected.
Elapsed: 00:00:00.03
可以看到对比前2个SQL:
250w6cua1mfa0
cxn8artthq7p8
执行计划一样,都是HASH JOIN SEMI。
对比后两个SQL:
1588n6cc48yv0
99fkm9p94agcf
执行计划也一样,都是HASH JOIN RIGHT SEMI。
所以,在新版本的数据库中,确实是不用再关注这个问题,优化器会帮助我们做好最优的查询转换。
小知识:IN和EXISTS的用法及效率验证的更多相关文章
- WPF小知识,MessageBox的多种用法
我们在程序中经常会用到MessageBox. 现将其常见用法总结如下: 1.MessageBox.Show("Hello~~~~"); 最简单的,只显示提示信息. 2.Messag ...
- 12个你未必知道的CSS小知识
虽然CSS并不是一种很复杂的技术,但就算你是一个使用CSS多年的高手,仍然会有很多CSS用法/属性/属性值你从来没使用过,甚至从来没听说过. 1.CSS的color属性并非只能用于文本显示 对于CSS ...
- python小技巧 小知识
python小技巧 小知识 python系统变量(修改调用shell命令路径)或用户空间说明 20150418 python调用系统命令,报找不到.怎么办? 类似执行shell的: [ -f /etc ...
- Mysql中EXISTS关键字用法、总结
在做教务系统的时候,一个学生(alumni_info)有多个教育经历(alumni_education),使用的数据库是mysql,之前使用左链接查询的,发现数据量才只有几万条时,查询就很慢了,早上想 ...
- Linux小知识:rm -rf/*会将系统全部删除吗
Linux小知识:rm -rf/*会将系统全部删除吗 本文是学习笔记,视频地址为:https://www.bilibili.com/video/av62839850 执行上面的命令并不会删除所有内容( ...
- Oracle-where exists()、not exists() 、in()、not in()用法以及效率差异
0.exists() 用法: select * from T1 where exists(select 1 from T2 where T1.a=T2.a) 其中 "select 1 fro ...
- 蓝牙Bluetooth技术小知识
蓝牙Bluetooth技术以及广泛的应用于各种设备,并将继续在物联网IoT领域担任重要角色.下面搜集整理了一些关于蓝牙技术的小知识,以备参考. 蓝牙Bluetooth技术始创于1994年,其名字来源于 ...
- HTML+CSS中的一些小知识
今天分享一些HTML.CSS的小知识,希望能够对大家有所帮助! 1.解决网页乱码的问题:最重要的是要保证各个环节的字符编码一致! (1)编辑器的编辑环境的字符集(默认字符集):Crtl+U 常见的编码 ...
- iOS APP开发的小知识(分享)
亿合科技小编发现从2007年第一款智能手机横空出世,由此开启了人们的移动智能时代.我们从一开始对APP的陌生,到现在的爱不释手,可见APP开发的出现对我们的生活改变有多巨大.而iOS AP ...
- SQL中EXISTS的用法
比如在Northwind数据库中有一个查询为SELECT c.CustomerId,CompanyName FROM Customers cWHERE EXISTS(SELECT OrderID FR ...
随机推荐
- js基础篇--对象
一.创建对象 对象直接量和 new Object (构造函数)与 Object.create 创建对象的区别 1.对象直接量和 new Object (构造函数) 原型都是Object 的 pro ...
- js 基础篇--保留字
1.js把一些标识符拿出来用作自己的关键字.因此,就不能再在程序中把这些关键字用作标识符了: 1 break delete function return typeof 2 case do if sw ...
- hive:使用concat_ws实现 array转string案例
concat_ws(',',collect_set(if(step_name <> '',step_name,null))) AS step_names,
- 【已解决】xlwings库合并单元格,不报错,不执行
源代码如下: import xlwings as xw app = xw.App(visible=True, add_book=False) app.display_alerts = False ap ...
- 通达OA实施的小总结
1.表格中带有复选框的单独一行单元格(一行两列 表头在第一列 复选框在第二列),在手机上进行显示时,这一行会把行表头屏蔽掉.2.日历控件不要用自定义格式,要不部分手机上无法使用.但是有些手机只能进行填 ...
- applicationContext使用注解代替
创建一个类SpringConfig @Configuration//证明这个类是spring的配置文件类 @ComponentScan("com.itheima")//扫描的哪些包 ...
- char值转换为int怎么才能不是ASCII值
直接将char类型的变量强制转换为int类型是不行的,那样只会传递变量所对应的ASCII码 怎么才能将char类型转换为int类型呢?String类型的可以通过方法转换为int类型.那是不是可以将ch ...
- JavaScript基础学习之一
目录 let和var之间的区别 作用域不同 变量提升 暂时性死区(temporal dead zone,简称 TDZ) 相同作用域下的重复声明 脚本调用 数据类型 Boolean Object 对象 ...
- 与用户交互 Scanner
与用户交互 Scanner Scanner对象 Java提供了一个工具类,可以用以获取用户的输入.java.util.Scanner 是Java5的新特征 基本语法 Scanner s = new S ...
- AD使用积累 - 板子上开孔的方法
有时候画板子时需要需要在板子上开一些槽孔,可以参考如下两种方法: 第一种方法:封闭曲线转换为槽孔. 1.在机械层画一个封闭图形或者画一根线: 2.选中这个图形或线,选择工具 - 转换 - 以选中的元素 ...