环境: 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的用法及效率验证的更多相关文章

  1. WPF小知识,MessageBox的多种用法

    我们在程序中经常会用到MessageBox. 现将其常见用法总结如下: 1.MessageBox.Show("Hello~~~~"); 最简单的,只显示提示信息. 2.Messag ...

  2. 12个你未必知道的CSS小知识

    虽然CSS并不是一种很复杂的技术,但就算你是一个使用CSS多年的高手,仍然会有很多CSS用法/属性/属性值你从来没使用过,甚至从来没听说过. 1.CSS的color属性并非只能用于文本显示 对于CSS ...

  3. python小技巧 小知识

    python小技巧 小知识 python系统变量(修改调用shell命令路径)或用户空间说明 20150418 python调用系统命令,报找不到.怎么办? 类似执行shell的: [ -f /etc ...

  4. Mysql中EXISTS关键字用法、总结

    在做教务系统的时候,一个学生(alumni_info)有多个教育经历(alumni_education),使用的数据库是mysql,之前使用左链接查询的,发现数据量才只有几万条时,查询就很慢了,早上想 ...

  5. Linux小知识:rm -rf/*会将系统全部删除吗

    Linux小知识:rm -rf/*会将系统全部删除吗 本文是学习笔记,视频地址为:https://www.bilibili.com/video/av62839850 执行上面的命令并不会删除所有内容( ...

  6. 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 ...

  7. 蓝牙Bluetooth技术小知识

    蓝牙Bluetooth技术以及广泛的应用于各种设备,并将继续在物联网IoT领域担任重要角色.下面搜集整理了一些关于蓝牙技术的小知识,以备参考. 蓝牙Bluetooth技术始创于1994年,其名字来源于 ...

  8. HTML+CSS中的一些小知识

    今天分享一些HTML.CSS的小知识,希望能够对大家有所帮助! 1.解决网页乱码的问题:最重要的是要保证各个环节的字符编码一致! (1)编辑器的编辑环境的字符集(默认字符集):Crtl+U 常见的编码 ...

  9. iOS APP开发的小知识(分享)

          亿合科技小编发现从2007年第一款智能手机横空出世,由此开启了人们的移动智能时代.我们从一开始对APP的陌生,到现在的爱不释手,可见APP开发的出现对我们的生活改变有多巨大.而iOS AP ...

  10. SQL中EXISTS的用法

    比如在Northwind数据库中有一个查询为SELECT c.CustomerId,CompanyName FROM Customers cWHERE EXISTS(SELECT OrderID FR ...

随机推荐

  1. springboot 整合 oss

    一.阿里云配置 获取 accessKeyIdaccessSecret 创建桶 bucketName 二.demo 1.oss.config import org.springframework.bea ...

  2. Python基础数据类型-Dictionary(字典)

    # -- coding: utf-8 -- # @time : 2022/7/19 21:51 # @file : 10pytest基本数据类型-dic.py # @software: pycharm ...

  3. to_csv()导入数据乱码问题

    制定编码: utf_8 -->utf_8_sig 修改后代码code: df.to_csv('data3.csv',index=False,encoding='utf_8_sig')

  4. grub-mkrescue:错误: `mformat` invocation failed

    跟着兴业视频做操作系统的时候遇到了这个问题 解决方法: sudo apt-get install mtools 参考: (40条消息) vs code连接远程Ubuntu编写操作系统,grub-mkr ...

  5. clamav测试用例 API

    最近接触到clamav这一块,本身是一个很简单的任务,只需要调用他的API对文件进行检测即可,但是在进行大量搜索发现,网上最多只有API的讲解,且质量层次不齐,这可为难住我了,作为一个名副其实的&qu ...

  6. python3GUI--实用!B站视频下载工具(附源码)

    目录 一.准备工作 二.预览 1.启动 2.解析 3.下载中 4.下载完成 5.结果 三.设计流程 1.bilibili_video_spider 2.视频json的查找 四.源代码 1.Bilibi ...

  7. Linux系列---【设置ssh连接超时时间】

    设置ssh连接超时时间 shell工具总是不断的超时,上个厕所就断开了,很不方便,这里根据自己习惯设置一下. echo "export TMOUT=600" >> /e ...

  8. NOIP2013普及组

    T1]记数问题 试计算在区间1 到n 的所有整数中,数字x(0 ≤ x ≤ 9)共出现了多少次?例如,在1到11 中,即在1.2.3.4.5.6.7.8.9.10.11中,数字1 出现了4 次. 其实 ...

  9. Spring 笔记三 AOP

    1.AOP 概述 AOP (Aspect-Oriented  Programming,面向切面编程):是一种新的方法论,是对传统 OOP (Object-Oriented  Programming,面 ...

  10. 转载·Pycharm Pro“This license 56ZS5PQ1RF has been cancelled” 激活码失效处理记录

    今天打开许久没用的Pycharm提示激活码过期,激活提示:"This license 56ZS5PQ1RF has been cancelled" 解决方法如下 首先修改hosts ...