全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

oracle中not exists对外层查询的影响详解

前言

最近同事发现了一个问题,在12c中跑的buffer get很高,但是在10g中跑的buffer很低。怀疑是不是12c的优化器有问题。

这个10g的环境和12c的环境,数据量大致一样,只是有很少部分的不同,但是就是这个很少部分不同,造成了not exists中的子查询返回不同的值,进而对外层查询产生不同的影响。

我们来用如下的代码模拟一下。

初始化数据:

--10g
drop table t1;
drop table t2;
 
create table t1 (id number,name varchar2(20),dep_id varchar2(10));
create table t2 (id number,name varchar2(20),dep_id varchar2(10));
 
insert into t1 select rownum,'a','kk' from dual connect by level <=3000000;
insert into t2 select rownum,'a','kk' from dual connect by level <=1000000;
insert into t2 select rownum,'a','mm' from dual;
 
commit;
 
 
--12c
drop table t1;
drop table t2;
 
create table t1 (id number,name varchar2(20),dep_id varchar2(10));
create table t2 (id number,name varchar2(20),dep_id varchar2(10));
 
 
insert into t1 select rownum,'a','kk' from dual connect by level <=3000000;
insert into t2 select rownum,'a','kk' from dual connect by level <=1000000;
 
commit;

我们看到,12c的数据和10g只是有很少的差别,t1表12c和10g都一样,t2表在12c只是少了一行数据。

--10g
SQL> select dep_id,count(*) from t1 group by dep_id;
 
DEP_ID     COUNT(*)
-------------------- ----------
kk      3000000
 
SQL> select dep_id,count(*) from t2 group by dep_id;
 
DEP_ID     COUNT(*)
-------------------- ----------
mm       1
kk      1000000
 
SQL>
 
 
--12c
SQL> select dep_id,count(*) from t1 group by dep_id;
 
DEP_ID     COUNT(*)
-------------------- ----------
kk      3000000
 
SQL> select dep_id,count(*) from t2 group by dep_id;
 
DEP_ID     COUNT(*)
-------------------- ----------
kk      1000000
 
SQL>

我们将要执行的sql语句是:

select count(*)
 from t1, t2
 where t1.id = t2.id
 and t1.dep_id = 'kk'
 and not exists (select 1
   from t1, t2
   where t1.id = t2.id
   and t2.dep_id = 'mm');

我们先来看执行情况的差距,10g的bufferget小,12c多:

--10g
SQL> select /*+ gather_plan_statistics */ count(*) from t1,t2 where t1.id=t2.id and t1.dep_id='kk' and not exists (select 1 from t1,t2 where t1.id=t2.id and t2.dep_id='mm');
 
 COUNT(*)
----------
   0
 
SQL> select* from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
 
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 22t5mb43w55pr, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from t1,t2 where t1.id=t2.id and t1.dep_id='kk' and not
exists (select 1 from t1,t2 where t1.id=t2.id and t2.dep_id='mm')
 
Plan hash value: 3404612428
 
------------------------------------------------------------------------------------------------------------------
| Id | Operation   | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT  |  |  1 |  |  1 |00:00:00.02 | 2086 |  |  |   |
| 1 | SORT AGGREGATE  |  |  1 |  1 |  1 |00:00:00.02 | 2086 |  |  |   |
|* 2 | FILTER    |  |  1 |  |  0 |00:00:00.02 | 2086 |  |  |   |
|* 3 | HASH JOIN   |  |  0 | 901K|  0 |00:00:00.01 |  0 | 39M| 5518K|   |
| 4 |  TABLE ACCESS FULL| T2 |  0 | 901K|  0 |00:00:00.01 |  0 |  |  |   |
|* 5 |  TABLE ACCESS FULL| T1 |  0 | 2555K|  0 |00:00:00.01 |  0 |  |  |   |
|* 6 | HASH JOIN   |  |  1 |  23 |  1 |00:00:00.02 | 2086 | 1517K| 1517K| 612K (0)|
|* 7 |  TABLE ACCESS FULL| T2 |  1 |  23 |  1 |00:00:00.02 | 2082 |  |  |   |
| 8 |  TABLE ACCESS FULL| T1 |  1 | 2555K|  1 |00:00:00.01 |  4 |  |  |   |
------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
 2 - filter( IS NULL)
 3 - access("T1"."ID"="T2"."ID")
 5 - filter("T1"."DEP_ID"='kk')
 6 - access("T1"."ID"="T2"."ID")
 7 - filter("T2"."DEP_ID"='mm')
 
Note
-----
 - dynamic sampling used for this statement
 
 
34 rows selected.
 
SQL>
 
 
--12c
SQL> select /*+ gather_plan_statistics */ count(*) from t1,t2 where t1.id=t2.id and t1.dep_id='kk' and not exists (select 1 from t1,t2 where t1.id=t2.id and t2.dep_id='mm');
 
 COUNT(*)
----------
 1000000
 
SQL> select* from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
 
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 22t5mb43w55pr, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from t1,t2 where
t1.id=t2.id and t1.dep_id='kk' and not exists (select 1 from t1,t2
where t1.id=t2.id and t2.dep_id='mm')
 
Plan hash value: 1692274438
 
--------------------------------------------------------------------------------------------------------------------
| Id | Operation    | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT  |  |  1 |  |  1 |00:00:00.79 | 10662 |  | |  |
| 1 | SORT AGGREGATE  |  |  1 |  1 |  1 |00:00:00.79 | 10662 |  | |  |
|* 2 | FILTER    |  |  1 |  | 1000K|00:00:00.74 | 10662 |  | |  |
|* 3 | HASH JOIN   |  |  1 | 1215K| 1000K|00:00:00.52 | 8579 | 43M| 6111K| 42M (0)|
| 4 |  TABLE ACCESS FULL | T2 |  1 | 1215K| 1000K|00:00:00.01 | 2083 |  | |  |
|* 5 |  TABLE ACCESS FULL | T1 |  1 | 2738K| 3000K|00:00:00.07 | 6496 |  | |  |
|* 6 | HASH JOIN RIGHT SEMI|  |  1 |  35 |  0 |00:00:00.02 | 2083 | 1245K| 1245K| 461K (0)|
|* 7 |  TABLE ACCESS FULL | T2 |  1 |  23 |  0 |00:00:00.02 | 2083 |  | |  |
| 8 |  TABLE ACCESS FULL | T1 |  0 | 2738K|  0 |00:00:00.01 |  0 |  | |  |
--------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
 2 - filter( IS NULL)
 3 - access("T1"."ID"="T2"."ID")
 5 - filter("T1"."DEP_ID"='kk')
 6 - access("T1"."ID"="T2"."ID")
 7 - filter("T2"."DEP_ID"='mm')
 
Note
-----
 - dynamic statistics used: dynamic sampling (level=2)
 
 
35 rows selected.
 
SQL>
SQL>

可以看到第23,24行,在10g中运行时,buffers是0,而在12c中,即78,79行,buffer是2083+6496。

也就是说在10g中,外层查询不进行t1和t2的扫描,直接返回结果了,而在12c中,外层查询还要进行t1表和t2表层扫描才返回结果。

这其实不是10g和12c的差别,而是not exists的返回数据对外层的影响。子查询要返回0行记录,才满足not exist的条件,从而返回外层查询结果。

在10g中,子查询返回了一行记录

--10g
SQL> select 1 from t1,t2 where t1.id=t2.id and t2.dep_id='mm';
 
   1
----------
   1
 
SQL>

不满足not exists(即0行才满足),所以,也就不用在外层继续查询了。直接返回记录0行。

在12c中,子查询返回0行记录,满足not exist的条件,所以还需要在外层查询中继续查询。

--12c
SQL> select count(*) from t1,t2 where t1.id=t2.id and t2.dep_id='kk';
 
 COUNT(*)
----------
 1000000
 
SQL> set line 1000
SQL> set pages 1000
SQL> col PLAN_TABLE_OUTPUT for a250
SQL>
SQL>
SQL> select /*+ gather_plan_statistics */ count(*) from t1,t2 where t1.id=t2.id and t1.dep_id='kk' and not exists (select 1 from t1,t2 where t1.id=t2.id and t2.dep_id='kk');
 
 COUNT(*)
----------
   0
 
SQL> select* from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
 
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID c5hj2p2jt1fxf, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from t1,t2 where
t1.id=t2.id and t1.dep_id='kk' and not exists (select 1 from t1,t2
where t1.id=t2.id and t2.dep_id='kk')
 
Plan hash value: 1692274438
 
--------------------------------------------------------------------------------------------------------------------
| Id | Operation    | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT  |  |  1 |  |  1 |00:00:00.28 | 2087 |  | |  |
| 1 | SORT AGGREGATE  |  |  1 |  1 |  1 |00:00:00.28 | 2087 |  | |  |
|* 2 | FILTER    |  |  1 |  |  0 |00:00:00.28 | 2087 |  | |  |
|* 3 | HASH JOIN   |  |  0 | 1215K|  0 |00:00:00.01 |  0 | 69M| 7428K|   |
| 4 |  TABLE ACCESS FULL | T2 |  0 | 1215K|  0 |00:00:00.01 |  0 |  | |  |
|* 5 |  TABLE ACCESS FULL | T1 |  0 | 2738K|  0 |00:00:00.01 |  0 |  | |  |
|* 6 | HASH JOIN RIGHT SEMI|  |  1 | 2738K|  1 |00:00:00.28 | 2087 | 43M| 6111K| 42M (0)|
|* 7 |  TABLE ACCESS FULL | T2 |  1 | 1215K| 1000K|00:00:00.12 | 2083 |  | |  |
| 8 |  TABLE ACCESS FULL | T1 |  1 | 2738K|  1 |00:00:00.01 |  4 |  | |  |
--------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
 2 - filter( IS NULL)
 3 - access("T1"."ID"="T2"."ID")
 5 - filter("T1"."DEP_ID"='kk')
 6 - access("T1"."ID"="T2"."ID")
 7 - filter("T2"."DEP_ID"='kk')
 
Note
-----
 - dynamic statistics used: dynamic sampling (level=2)
 
 
35 rows selected.
 
SQL>

可以看到第38,39行的buffer为0.

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。


# oracle  # not  # exists  # oracle中not  # oracle中的not  # Oracle In和exists not in和not exists的比较分析  # Oracle23ai 新特性IF [NOT] EXISTS语法支持的使  # EXISTS关键字在Oracle中的简单使用例子  # 简述Oracle中in和exists的不同  # oracle中exists和not exists用法举例详解  # 是有  # 而在  # 可以看到  # 也就  # 要在  # 很高  # 少了  # 造成了  # 一个问题  # 这篇文章  # 用在  # 很低  # 还需  # 查询结果  # 执行情况  # 不满足  # 来用  # 发现了  # 也就是说  # 但是在 


相关文章: 如何在IIS管理器中快速创建并配置网站?  做企业网站制作流程,企业网站制作基本流程有哪些?  网站图片在线制作软件,怎么在图片上做链接?  常州企业网站制作公司,全国继续教育网怎么登录?  如何通过西部建站助手安装IIS服务器?  手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?  武汉网站制作费用多少,在武汉武昌,建面100平方左右的房子,想装暖气片,费用大概是多少啊?  建站VPS配置与SEO优化指南:关键词排名提升策略  公司门户网站制作流程,华为官网怎么做?  广德云建站网站建设方案与建站流程优化指南  高端企业智能建站程序:SEO优化与响应式模板定制开发  金*站制作公司有哪些,金华教育集团官网?  建站主机是什么?如何选择适合的建站主机?  安云自助建站系统如何快速提升SEO排名?  名字制作网站免费,所有小说网站的名字?  广平建站公司哪家专业可靠?如何选择?  攀枝花网站建设,攀枝花营业执照网上怎么年审?  建站主机服务器选型指南与性能优化方案解析  中山网站制作网页,中山新生登记系统登记流程?  如何快速搭建FTP站点实现文件共享?  如何快速配置高效服务器建站软件?  免费制作小说封面的网站有哪些,怎么接网站批量的封面单?  家庭建站与云服务器建站,如何选择更优?  建站主机SSH密钥生成步骤及常见问题解答?  微信小程序 五星评分(包括半颗星评分)实例代码  定制建站流程解析:需求评估与SEO优化功能开发指南  ui设计制作网站有哪些,手机UI设计网址吗?  香港服务器租用费用高吗?如何避免常见误区?  如何零成本快速生成个人自助网站?  如何在橙子建站上传落地页?操作指南详解  建站之星Pro快速搭建教程:模板选择与功能配置指南  网站制作软件免费下载安装,有哪些免费下载的软件网站?  三星网站视频制作教程下载,三星w23网页如何全屏?  建站主机选购指南:核心配置优化与品牌推荐方案  如何制作网站标识牌,动态网站如何制作(教程)?  建站中国必看指南:CMS建站系统+手机网站搭建核心技巧解析  如何获取免费开源的自助建站系统源码?  如何在阿里云虚拟主机上快速搭建个人网站?  专业网站制作服务公司,有哪些网站可以免费发布招聘信息?  如何在建站宝盒中设置产品搜索功能?  建站主机助手选型指南:2025年热门推荐与高效部署技巧  建站之星下载版如何获取与安装?  网站制作模板下载什么软件,ppt模板免费下载网站?  武清网站制作公司,天津武清个人营业执照注销查询系统网站?  ,怎么在广州志愿者网站注册?  javascript中对象的定义、使用以及对象和原型链操作小结  建站主机类型有哪些?如何正确选型  招商网站制作流程,网站招商广告语?  jQuery 常见小例汇总  如何快速使用云服务器搭建个人网站? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。