如何优化一条含有大量exist和left join 优化的sql?

揭秘SQL优化技巧 改善数据库性能
  这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础,重点讲述如何优化SQL,来提高数据库的性能。  优化目标  1、减少 IO 次数  IO永远是数据库最容易瓶颈...
   
  这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础,重点讲述如何优化SQL,来提高数据库的性能。
  优化目标
  1、减少 IO 次数
  IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当然,也是收效最明显的优化手段。
  2、降低CPU计算
  除了 IO 瓶颈之外,SQL优化中需要考虑的就是CPU运算量的优化了。order by, group by,distinct & 都是消耗 CPU 的大户(这些操作基本上都是 CPU 处理内存中的数据比较运算)。当我们的 IO 优化做到一定阶段之后,降低 CPU 计算也就成为了我们 SQL 优化的重要目标
  优化方法
  1、改变 SQL 执行计划
  明确了优化目标之后,我们需要确定达到我们目标的方法。对于 SQL 语句来说,达到上述2个目标的方法其实只有一个,那就是改变 SQL 的执行计划,让他尽量&少走弯路&,尽量通过各种&捷径&来找到我们需要的数据,以达到 &减少 IO 次数& 和 &降低 CPU 计算& 的目标
  常见误区
  1、count(1)和count(primary_key) 优于 count(*)
  很多人为了统计记录条数,就使用 count(1) 和 count(primary_key) 而不是 count(*) ,他们认为这样性能更好,其实这是一个误区。对于有些场景,这样做可能性能会更差,应为数据库对 count(*) 计数操作做了一些特别的优化。
  2、count(column) 和 count(*) 是一样的
  这个误区甚至在很多的资深工程师或者是 DBA 中都普遍存在,很多人都会认为这是理所当然的。实际上,count(column) 和 count(*) 是一个完全不一样的操作,所代表的意义也完全不一样。
  count(column) 是表示结果集中有多少个column字段不为空的记录
  count(*) 是表示整个结果集有多少条记录
  3、select a,b from & 比 select a,b,c from & 可以让数据库访问更少的数据量
  这个误区主要存在于大量的开发人员中,主要原因是对数据库的存储原理不是太了解。
  实际上,大多数关系型数据库都是按照行(row)的方式存储,而数据存取操作都是以一个固定大小的IO单元(被称作 block 或者 page)为单位,一般为4KB,8KB& 大多数时候,每个IO单元中存储了多行,每行都是存储了该行的所有字段(lob等特殊类型字段除外)。
  所以,我们是取一个字段还是多个字段,实际上数据库在表中需要访问的数据量其实是一样的。
  当然,也有例外情况,那就是我们的这个查询在索引中就可以完成,也就是说当只取 a,b两个字段的时候,不需要回表,而c这个字段不在使用的索引中,需要回表取得其数据。在这样的情况下,二者的IO量会有较大差异。
  4、order by 一定需要排序操作
  我们知道索引数据实际上是有序的,如果我们的需要的数据和某个索引的顺序一致,而且我们的查询又通过这个索引来执行,那么数据库一般会省略排序操作,而直接将数据返回,因为数据库知道数据已经满足我们的排序需求了。
  实际上,利用索引来优化有排序需求的 SQL,是一个非常重要的优化手段
  延伸阅读:MySQL ORDER BY 的实现分析 ,MySQL 中 GROUP BY 基本实现原理 以及 MySQL DISTINCT 的基本实现原理 这3篇文章中有更为深入的分析,尤其是第一篇
  5、执行计划中有 filesort 就会进行磁盘文件排序
  有这个误区其实并不能怪我们,而是因为 MySQL 开发者在用词方面的问题。filesort 是我们在使用 explain 命令查看一条 SQL 的执行计划的时候可能会看到在 &Extra& 一列显示的信息。
  实际上,只要一条 SQL 语句需要进行排序操作,都会显示&Using filesort&,这并不表示就会有文件排序操作。
  延伸阅读:理解 MySQL Explain 命令输出中的filesort,我在这里有更为详细的介绍
  基本原则
  1、尽量少 join
  MySQL 的优势在于简单,但这在某些方面其实也是其劣势。MySQL 优化器效率高,但是由于其统计信息的量有限,优化器工作过程出现偏差的可能性也就更多。对于复杂的多表 Join,一方面由于其优化器受限,再者在 Join 这方面所下的功夫还不够,所以性能表现离 Oracle 等关系型数据库前辈还是有一定距离。但如果是简单的单表查询,这一差距就会极小甚至在有些场景下要优于这些数据库前辈。
  2、尽量少排序
  排序操作会消耗较多的 CPU 资源,所以减少排序可以在缓存命中率高等 IO 能力足够的场景下会较大影响 SQL 的响应时间。
  对于MySQL来说,减少排序有多种办法,比如:
  上面误区中提到的通过利用索引来排序的方式进行优化
  减少参与排序的记录条数
  非必要不对数据进行排序
  3、尽量避免 select *
  很多人看到这一点后觉得比较难理解,上面不是在误区中刚刚说 select 子句中字段的多少并不会影响到读取的数据吗?
  是的,大多数时候并不会影响到 IO 量,但是当我们还存在 order by 操作的时候,select 子句中的字段多少会在很大程度上影响到我们的排序效率,这一点可以通过我之前一篇介绍 MySQL ORDER BY 的实现分析 的文章中有较为详细的介绍。
  此外,上面误区中不是也说了,只是大多数时候是不会影响到 IO 量,当我们的查询结果仅仅只需要在索引中就能找到的时候,还是会极大减少 IO 量的。
  4、尽量用 join 代替子查询
  虽然 Join 性能并不佳,但是和 MySQL 的子查询比起来还是有非常大的性能优势。MySQL 的子查询执行计划一直存在较大的问题,虽然这个问题已经存在多年,但是到目前已经发布的所有稳定版本中都普遍存在,一直没有太大改善。虽然官方也在很早就承认这一问题,并且承诺尽快解决,但是至少到目前为止我们还没有看到哪一个版本较好的解决了这一问题。
  5、尽量少 or
  当 where 子句中存在多个条件以&或&并存的时候,MySQL 的优化器并没有很好的解决其执行计划优化问题,再加上 MySQL 特有的 SQL 与 Storage 分层架构方式,造成了其性能比较低下,很多时候使用 union all 或者是union(必要的时候)的方式来代替&or&会得到更好的效果。
  6、尽量用 union all 代替 union
  union 和 union all 的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 CPU 运算,加大资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使用 union all 而不是 union。
  7、尽量早过滤
  这一优化策略其实最常见于索引的优化设计中(将过滤性更好的字段放得更靠前)。
  在 SQL 编写中同样可以使用这一原则来优化一些 Join 的 SQL。比如我们在多个表进行分页数据查询的时候,我们最好是能够在一个表上先过滤好数据分好页,然后再用分好页的结果集与另外的表 Join,这样可以尽可能多的减少不必要的 IO 操作,大大节省 IO 操作所消耗的时间。
  8、避免类型转换
  这里所说的&类型转换&是指 where 子句中出现 column 字段的类型和传入的参数类型不一致的时候发生的类型转换:
  人为在column_name 上通过转换函数进行转换
  直接导致 MySQL(实际上其他数据库也会有同样的问题)无法使用索引,如果非要转换,应该在传入的参数上进行转换
  由数据库自己进行转换
  如果我们传入的数据类型和字段类型不一致,同时我们又没有做任何类型转换处理,MySQL 可能会自己对我们的数据进行类型转换操作,也可能不进行处理而交由存储引擎去处理,这样一来,就会出现索引无法使用的情况而造成执行计划问题。
  9、优先优化高并发的 SQL,而不是执行频率低某些&大&SQL
  对于破坏性来说,高并发的 SQL 总是会比低频率的来得大,因为高并发的 SQL 一旦出现问题,甚至不会给我们任何喘息的机会就会将系统压跨。而对于一些虽然需要消耗大量 IO 而且响应很慢的 SQL,由于频率低,即使遇到,最多就是让整个系统响应慢一点,但至少可能撑一会儿,让我们有缓冲的机会。
  10、从全局出发优化,而不是片面调整
  SQL 优化不能是单独针对某一个进行,而应充分考虑系统中所有的 SQL,尤其是在通过调整索引优化 SQL 的执行计划的时候,千万不能顾此失彼,因小失大。
  11、尽可能对每一条运行在数据库中的SQL进行 explain
  优化 SQL,需要做到心中有数,知道 SQL 的执行计划才能判断是否有优化余地,才能判断是否存在执行计划问题。在对数据库中运行的 SQL 进行了一段时间的优化之后,很明显的问题 SQL 可能已经很少了,大多都需要去发掘,这时候就需要进行大量的 explain 操作收集执行计划,并判断是否需要进行优化。
  via IT168 技术
(责任编辑:phpcms)
本文关键字:
广告赞助商
最新视频推荐
Copyright (C) 2007-, All Rights Reserved 版权所有 . 沪ICP备号
地址:上海徐汇区零陵路585号 爱邦大厦26H座
传真(FAX):021-
电话(Tel):021-
PHP100 Website Powered by PHPCMS. For PHP100. 服务器维护:阿里巴巴-阿里云&&&&SQL语句优化——in,not in,exists,not exists, left join...on博客所需SQL语句.txt
SQL语句优化——in,not in,exists,not exists, left join...on博客所需SQL语句.txt
SQL语句优化——in,not in,exists,not exists, left join...on博客所需SQL语句.txt欢迎下载!
若举报审核通过,可奖励20下载分
被举报人:
wangshuxuncom
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
VIP下载&&免积分60元/年(1200次)
您可能还需要
数据库下载排行关于sql left join 的优化问题,求大神给下思路
[问题点数:20分]
关于sql left join 的优化问题,求大神给下思路
[问题点数:20分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。1773人阅读
分类: Oracle
& & 在ORACLE 11G大行其道的今天,还有很多人受早期版本的影响,记住一些既定的规则,
& &1.子查询结果集小,用IN
& &2.外表小,子查询表大,用EXISTS
& & &这是完全错误的观点。在8i时代,这经常是正确的,但是现在已经11G了,马上12C就要面世了。其实在ORACLE 9i CBO就已经优化了IN,EXISTS的区别,ORACLE优化器有个查询转换器,很多SQL虽然写法不同,但是ORACLE优化器会根据既定规则进行查询重写,重写为优化器觉得效率最高的SQL,所以可能SQL写法不同,但是执行计划却是完全一样的。
& & &IN与EXISTS有一点要记住:IN一般是用于非相关子查询,而EXISTS一般用于相关子查询。当然IN也可以用于相关子查询,EXISTS也可以用于非相关子查询。但是这区别很重要,虽然优化器很强大,但是查询转换是有一定的限制的,在EXISTS性能低下,无法进行相关查询转换,比如不能UNNEST SUBQUERY,那么可能我们需要改写SQL,通常可以用IN/JOIN等改写相关子查询,或对于含有OR的SEMI JOIN改为UNION
ALL/UNION的形式。
& &&下面就用例子说明一下:
DROP TABLE
DROP TABLE
CREATE TABLE a AS SELECT * FROM hr.
CREATE TABLE b AS SELECT * FROM &hr.
--反复插入,构造20万行+
INSERT INTO a SELECT * FROM
INSERT INTO b SELECT * FROM
&dbms_stats.gather_table_stats(ownname =& USER,tabname =& 'a',estimate_percent =& 100,cascade =& TRUE);
& dbms_stats.gather_table_stats(ownname =& USER,tabname =& 'b',estimate_percent =& 100,cascade =& TRUE);
1.测试IN,EXISTS在简单查询中,是等价的
SQL& set autotrace traceonly exp
SQL& SELECT * FROM a
& 2 &WHERE EXISTS(
& 3 &SELECT 1 FROM b WHERE a.employee_id=b.employee_id);
----------------------------------------------------------
Plan hash value:&<span style="color:#E56356
---------------------------------------------------------------------------------
| Id &| Operation & & & & & & &| Name & | Rows &| Bytes | Cost (%CPU)| Time & & |
---------------------------------------------------------------------------------
| & 0 | SELECT STATEMENT & & & | & & & &| & 217K| & &15M| &1375 & (2)| 00:00:17 |
|* &1 | &HASH JOIN & & & & & & | & & & &| & 217K| & &15M| &1375 & (2)| 00:00:17 |
| & 2 | & SORT UNIQUE & & & & &| & & & &| & 217K| & 848K| & 126 & (1)| 00:00:02 |
| & 3 | & &INDEX FAST FULL SCAN| IDX2_B | & 217K| & 848K| & 126 & (1)| 00:00:02 |
| & 4 | & TABLE ACCESS FULL & &| A & & &| & 217K| & &14M| & 620 & (1)| 00:00:08 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
& &1 - access(&A&.&EMPLOYEE_ID&=&B&.&EMPLOYEE_ID&)
SQL& SELECT * FROM a
& 2 &WHERE a.employee_id IN (SELECT b.employee_id FROM b);
----------------------------------------------------------
Plan hash value:&<span style="color:#E56356
---------------------------------------------------------------------------------
| Id &| Operation & & & & & & &| Name & | Rows &| Bytes | Cost (%CPU)| Time & & |
---------------------------------------------------------------------------------
| & 0 | SELECT STATEMENT & & & | & & & &| & 217K| & &15M| &1375 & (2)| 00:00:17 |
|* &1 | &HASH JOIN & & & & & & | & & & &| & 217K| & &15M| &1375 & (2)| 00:00:17 |
| & 2 | & SORT UNIQUE & & & & &| & & & &| & 217K| & 848K| & 126 & (1)| 00:00:02 |
| & 3 | & &INDEX FAST FULL SCAN| IDX2_B | & 217K| & 848K| & 126 & (1)| 00:00:02 |
| & 4 | & TABLE ACCESS FULL & &| A & & &| & 217K| & &14M| & 620 & (1)| 00:00:08 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
& &1 - access(&A&.&EMPLOYEE_ID&=&B&.&EMPLOYEE_ID&)
& 可以看出,两个计划完全没有区别。类&#20284;于ORACLE查询重写为:
&SELECT a.* FROM a,(SELECT DISTINCT b.employee_id FROM b) b1 WHERE a.employee_id=b1.employee_
看看8i时代的区别:
SQL& SELECT/*&#43;optimizer_features_enable('8.1.7')*/ * FROM a
& 2 &WHERE EXISTS(
& 3 &SELECT 1 FROM b WHERE a.employee_id=b.employee_id);
已用时间: &00: 00: 00.00
----------------------------------------------------------
Plan hash value:
-------------------------------------------------------------
| Id &| Operation & & & & &| Name & | Rows &| Bytes | Cost &|
-------------------------------------------------------------
| & 0 | SELECT STATEMENT & | & & & &| 10854 | & 731K| & 344 |
&FILTER & & & & & &| & & & &| & & & | & & & | & & & |
| & 2 | & TABLE ACCESS FULL| A & & &| 10854 | & 731K| & 344 |
|* &3 | & INDEX RANGE SCAN | IDX2_B | &2049 | &8196 | & & 5 |
-------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
& &1 - filter( EXISTS (SELECT 0 FROM &B& &B& WHERE
& & & & & & & &B&.&EMPLOYEE_ID&=:B1))
& &3 - access(&B&.&EMPLOYEE_ID&=:B1)
& &- cpu costing is off (consider enabling it)
SQL& SELECT/*&#43;optimizer_features_enable('8.1.7')*/ * FROM a
& 2 &WHERE a.employee_id IN (SELECT b.employee_id FROM b);
已用时间: &00: 00: 00.00
----------------------------------------------------------
Plan hash value:
-------------------------------------------------------------------------
| Id &| Operation & & & & & &| Name & & | Rows &| Bytes |TempSpc| Cost &|
-------------------------------------------------------------------------
| & 0 | SELECT STATEMENT & & | & & & & &| & 217K| & &16M| & & & | &1126 |
&HASH JOIN & & & & & | & & & & &| & 217K| & &16M| & & & | &1126 |
| & 2 | & VIEW & & & & & & & | VW_NSO_1 | & 106 | &1378 | & & & | & 779 |
| & 3 | & &SORT UNIQUE & & & | & & & & &| & 106 | & 424 | &2576K| & 779 |
| & 4 | & & TABLE ACCESS FULL| B & & & &| & 217K| & 848K| & & & | & 344 |
| & 5 | & TABLE ACCESS FULL &| A & & & &| & 217K| & &14M| & & & | & 344 |
-------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
& &1 - access(&A&.&EMPLOYEE_ID&=&EMPLOYEE_ID&)
& &- cpu costing is off (consider enabling it)
& & 显然,在8i时代,还是有明显的区别,EXISTS是主表驱动,走的FILTER,如果主表返回行很多,那么必然效率会低,如果主表小,内表,内表能走索引,是很好的,IN走HASH JOIN,受内表
驱动,内表返回行少,效率高。当然具体情况肯定会很复杂,这里不做研究了,因为8i已经是过去式了。
2.遇到优化器限制的做法:改写SQL
& & & &ORACLE优化器虽然已经很强大,但是还有很多限制,比如无法UNNEST的限制如子查询有CONNECT BY,SET操作,ROWNUM,关联子查询内部包含分组函数等。还比如SEMI JOIN.ANTI JOIN条件带OR的形式等。这时候,我们常用的优化方式就是SQL的等价改写,这要根据具体的业务和数据特点,来重写等价的SQL,千万别改写成结果不等价,那就糟糕了。
& & &比如这个SQL:
SELECT * FROM a
WHERE EXISTS(
SELECT 1 FROM b WHERE a.department_id=b.department_id &GROUP BY b.department_id HAVING a.salary&=MAX(b.salary));
SQL& @display_cursor
SQL_ID &dgc8b80sxwct2, child number 1
-------------------------------------
SELECT * FROM a WHERE EXISTS( SELECT 1 FROM b WHERE
a.department_id=b.department_id &GROUP BY b.department_id HAVING
a.salary&=MAX(b.salary))
Plan hash value:
-----------------------------------------------------------------------------------------
| Id &| Operation & & & & & & &| Name | Starts | E-Rows | A-Rows | & A-Time & | Buffers |
-----------------------------------------------------------------------------------------
| & 0 | SELECT STATEMENT & & & | & & &| & & &1 | & & & &| &2:13.61 | & &
|* &1 | &FILTER & & & & & & & &| & & &| & & &1 | & & & &| &2:13.61 | & & &32M|
| & 2 | & TABLE ACCESS FULL & &| A & &| & & &1 | & &217K| & &217K|00:00:00.20 | & &3733 |
|* &3 | & FILTER & & & & & & & | & & &|
&14403 | & & & &| & 2058 |<span style="background-color:#E5:13.20 | & & &32M|
| & 4 | & &SORT GROUP BY NOSORT| & & &|
&14403 | & & &1 | &1:13.17 | & & &32M|
|* &5 | & & TABLE ACCESS FULL &| B & &| &<span style="color:#E5
| &19745 | & &973M|00:06:17.21 | & & &32M|
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
& &1 - filter( IS NOT NULL)
& &3 - filter(MAX(&B&.&SALARY&)&=:B1)
& &5 - filter(&B&.&DEPARTMENT_ID&=:B1)
& &这是个很简单的SQL,但是因为使用了EXISTS关联子查询,并且内部有分组操作,无法进行有效的查询转换,走了FILTER操作,FILTER操作类&#20284;于NESTED LOOPS,但是不同于NESTED LOOPS的是,他还可以通过条件判断,是否走子步骤。这里全表扫描B 14403次(这是无法忍受的,特别遇到大表,甭想跑出来了)。
& 那么如何优化这种SQL呢,要改写,改写为JOIN形式:
&SQL& SELECT * FROM a,(SELECT department_id,MAX(b.salary) max_salary FROM b GROUP BY b.department_id) b1
& 2 &WHERE a.department_id=b1.department_id AND a.salary&=b1.max_
已选择22528行。
已用时间: &00: 00: 00.64
----------------------------------------------------------
Plan hash value:
-----------------------------------------------------------------------------
| Id &| Operation & & & & & &| Name | Rows &| Bytes | Cost (%CPU)| Time & & |
-----------------------------------------------------------------------------
| & 0 | SELECT STATEMENT & & | & & &| 10854 | &1006K| &1250 & (2)| 00:00:16 |
|* &1 | &HASH JOIN & & & & & | & & &| 10854 | &1006K| &1250 & (2)| 00:00:16 |
| & 2 | & VIEW & & & & & & & | & & &| & &11 | & 286 | & 629 & (3)| 00:00:08 |
| & 3 | & &HASH GROUP BY & & | & & &| & &11 | & &88 | & 629 & (3)| 00:00:08 |
| & 4 | & & TABLE ACCESS FULL| B & &| & 217K| &1696K| & 620 & (1)| 00:00:08 |
| & 5 | & TABLE ACCESS FULL &| A & &| & 217K| & &14M| & 620 & (1)| 00:00:08 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
& &1 - access(&A&.&DEPARTMENT_ID&=&B1&.&DEPARTMENT_ID&)
& & & &filter(&A&.&SALARY&&=&B1&.&MAX_SALARY&)
----------------------------------------------------------
& & & & & 0 &recursive calls
& & & & & 0 &db block gets
& & & &5986 &consistent gets
& & & & & 0 &physical reads
& & & & & 0 &redo size
& & 1851483 &bytes sent via SQL*Net to client
& & & 16926 &bytes received via SQL*Net from client
& & & &1503 &SQL*Net roundtrips to/from client
& & & & & 0 &sorts (memory)
& & & & & 0 &sorts (disk)
& & & 22528 &rows processed
& & 从上面看出,逻辑读相对于没有改写之前的32M,时间9分钟,效率现在大幅度提升,时间变为00: 00: 00.64,l逻辑读变为5986次,因为走了HASH JOIN,相当于两表各扫描1次。
& 上面是通过将子查询改为JOIN的形式来优化,当然改写方式多样,下面用一个EXISTS改写为IN的方式来提高效率:
&SELECT * FROM a WHERE EXISTS(SELECT 1 FROM b WHERE &a.department_id=b.department_id AND a.employee_id=b.employee_id
&&START WITH b.employee_id =202 CONNECT BY PRIOR b.employee_id=b.manager_id);
SQL& set autotrace traceonly exp
SQL& &SELECT * FROM a WHERE EXISTS(SELECT 1 FROM b WHERE &a.department_id=b.department_id AND a.employee_id=b.employee_id
& 2 & &START WITH b.employee_id =202 CONNECT BY PRIOR b.employee_id=b.manager_id);
已用时间: &00: 00: 00.00
----------------------------------------------------------
Plan hash value:
---------------------------------------------------------------------------------------------------
| Id &| Operation & & & & & & & & & & & & & & & & &| Name | Rows &| Bytes | Cost (%CPU)| Time & & |
---------------------------------------------------------------------------------------------------
| & 0 | SELECT STATEMENT & & & & & & & & & & & & & | & & &| & 186 | 12834 | & 723K &(1)| 02:24:37 |
|* &1 | &FILTER & & & & & & & & & & & & & & & & & &| & & &| & & & | & & & | & & & & & &| & & & & &|
| & 2 | & TABLE ACCESS FULL & & & & & & & & & & & &| A & &| & 217K| & &14M| & 620 & (1)| 00:00:08 |
|* &3 | & FILTER & & & & & & & & & & & & & & & & & | & & &| & & & | & & & | & & & & & &| & & & & &|
|* &4 | & &CONNECT BY NO FILTERING WITH SW (UNIQUE)| & & &| & & & | & & & | & & & & & &| & & & & &|
| & 5 | & & TABLE ACCESS FULL & & & & & & & & & & &| B & &| & 217K| &2545K| & 620 & (1)| 00:00:08 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
& &1 - filter( EXISTS (SELECT 0 FROM &B& &B& WHERE &B&.&DEPARTMENT_ID&=:B1 AND
& & & & & & & &B&.&EMPLOYEE_ID&=:B2 START WITH &B&.&EMPLOYEE_ID&=202 CONNECT BY &B&.&MANAGER_ID&=PRIOR
& & & & & & & &B&.&EMPLOYEE_ID&))
& &3 - filter(&B&.&DEPARTMENT_ID&=:B1 AND &B&.&EMPLOYEE_ID&=:B2)
& &4 - access(&B&.&MANAGER_ID&=PRIOR &B&.&EMPLOYEE_ID&)
& & & &filter(&B&.&EMPLOYEE_ID&=202)
& &又是和前面类&#20284;的FILTER操作,这条SQL也要运行很长时间,FILTER操作不是不好,就像NESTED LOOPS一样,也有高效的时候,如果FILTER操作做的次数不多,而且分支操作可以高效实用索引,那么也是高效的,这得注意。
& 改写,以上查询可以很容易改写为IN的形式:
&SQL& SELECT * FROM a WHERE (a.department_id,a.employee_id) IN
& 2 & (SELECT b.department_id,b.employee_id FROM b &START WITH b.employee_id =202 CONNECT BY PRIOR b.employee_id=b.manager_id );
已用时间: &00: 00: 00.13
----------------------------------------------------------
Plan hash value:
--------------------------------------------------------------------------------------------------------------
| Id &| Operation & & & & & & & & & & & & & & & & | Name & & | Rows &| Bytes |TempSpc| Cost (%CPU)| Time & & |
--------------------------------------------------------------------------------------------------------------
| & 0 | SELECT STATEMENT & & & & & & & & & & & & &| & & & & &| &2048 | & 190K| & & & | &2466 & (1)| 00:00:30 |
|* &1 | &HASH JOIN RIGHT SEMI & & & & & & & & & & | & & & & &| &2048 | & 190K| &8064K| &2466 & (1)| 00:00:30 |
| & 2 | & VIEW & & & & & & & & & & & & & & & & & &| VW_NSO_1 | & 217K| &5514K| & & & | &1617 &(62)| 00:00:20 |
|* &3 | & &CONNECT BY NO FILTERING WITH START-WITH| & & & & &| & & & | & & & | & & & | & & & & & &| & & & |
| & 4 | & & TABLE ACCESS FULL & & & & & & & & & & | B & & & &| & 217K| &2545K| & & & | & 620 & (1)| 00:00:08 |
| & 5 | & TABLE ACCESS FULL & & & & & & & & & & & | A & & & &| & 217K| & &14M| & & & | & 620 & (1)| 00:00:08 |
--------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
& &1 - access(&A&.&DEPARTMENT_ID&=&DEPARTMENT_ID& AND &A&.&EMPLOYEE_ID&=&EMPLOYEE_ID&)
& &3 - access(&B&.&MANAGER_ID&=PRIOR &B&.&EMPLOYEE_ID&)
& & & &filter(&B&.&EMPLOYEE_ID&=202)
& & 走了HASH JOIN,这条SQL效率大增,基本在&1s内会返回结果。
& 在学习过程中,一定要亲自实践,不能遵循于从某个地方看到的规则,特别是N年前的规则,规则是有用的,但是规则也会不断滴更新的,如果规则发生了更新,但是在你的脑子里没有更新,你却不经过实践,就永远遵循这规则,那你对这方面的知识永远知之甚少或知而不全。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:30541次
排名:千里之外
原创:17篇
转载:11篇
(2)(7)(7)(5)(6)(1)

我要回帖

更多关于 left join 优化 的文章

 

随机推荐