exists和in的区别和优化
来源:互联网 发布:单片机常用芯片 编辑:程序博客网 时间:2024/06/05 20:11
在oracle中有exists、not exists来进行一些表连接操作,在普通情况下Oracle的执行计划如果使用到semi-join、anti-join方式来进行表连接的话,速度一遍很快,否则很慢。通过使用提示hash_sj hash_aj也可使执行计划走semi-join、anti-join。下面有两种不同的写法,都会走semi-joinSQL> create table dev.a1 as select * from dba_objects where rownum <= 10000;Table created.SQL> create table dev.a2 as 2 select * from (select t.*,rownum rd from dba_objects t) p where rd>5000 and rd<= 15000;Table created.SQL> create table dev.a3 as 2 select * from (select t.*,rownum rd from dba_objects t) p where rd>7500 and rd<= 17500;Table created.SQL> analyze table dev.a1 compute statistics;Table analyzed.SQL> analyze table dev.a2 compute statistics;Table analyzed.SQL> analyze table dev.a3 compute statistics;Table analyzed.SQL> set autotrace traceonly; SQL> set timing onSQL> set linesize 177SQL> /* Formatted on 2013/09/21 14:21:36 (QP5 v5.227.12220.39754) */SQL> SELECT a1.owner, COUNT (*) 2 FROM dev.a1 3 WHERE EXISTS 4 (SELECT /*+ hash_sj(a1 a2) */ 5 * 6 FROM dev.a2 7 WHERE a2.object_id = a1.object_id) 8 OR EXISTS 9 (SELECT /*+ hash_sj(a1 a2) */ 10 * 11 FROM dev.a3 12 WHERE a3.object_id = a1.object_id) 13 GROUP BY a1.owner;Elapsed: 00:00:00.18Execution Plan----------------------------------------------------------Plan hash value: 3327704572---------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 5 | 60 | 124 (2)| 00:00:02 || 1 | HASH GROUP BY | | 5 | 60 | 124 (2)| 00:00:02 ||* 2 | HASH JOIN SEMI | | 5082 | 60984 | 123 (1)| 00:00:02 || 3 | TABLE ACCESS FULL | A1 | 10000 | 80000 | 40 (0)| 00:00:01 || 4 | VIEW | VW_SQ_1 | 18422 | 73688 | 82 (0)| 00:00:01 || 5 | UNION-ALL | | | | | || 6 | TABLE ACCESS FULL| A3 | 8422 | 33688 | 38 (0)| 00:00:01 || 7 | TABLE ACCESS FULL| A2 | 10000 | 40000 | 44 (0)| 00:00:01 |---------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 2 - access("VW_COL_1"="A1"."OBJECT_ID")Statistics---------------------------------------------------------- 1 recursive calls 0 db block gets 406 consistent gets 0 physical reads 0 redo size 709 bytes sent via SQL*Net to client 520 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 5 rows processedSQL> SQL> /* Formatted on 2013/09/21 14:23:32 (QP5 v5.227.12220.39754) */SQL> SELECT x.owner, COUNT (*) 2 FROM (SELECT * 3 FROM dev.a1 4 WHERE EXISTS 5 (SELECT /*+ hash_sj(a1 a2)*/ 6 * 7 FROM dev.a2 8 WHERE a2.object_id = a1.object_id) 9 UNION ALL 10 SELECT * 11 FROM dev.a1 12 WHERE NOT EXISTS 13 (SELECT /*+ hash_aj(a1 p)*/ 14 * 15 FROM dev.a2 p 16 WHERE p.object_id = a1.object_id) 17 AND EXISTS 18 (SELECT /*+ hash_sj(a1 a3)*/ 19 * 20 FROM dev.a3 21 WHERE a3.object_id = a1.object_id)) x 22 GROUP BY x.owner;Elapsed: 00:00:00.03Execution Plan----------------------------------------------------------Plan hash value: 195072970---------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 5 | 25 | 210 (2)| 00:00:03 || 1 | HASH GROUP BY | | 5 | 25 | 210 (2)| 00:00:03 || 2 | VIEW | | 5108 | 25540 | 209 (2)| 00:00:03 || 3 | UNION-ALL | | | | | ||* 4 | HASH JOIN RIGHT SEMI | | 5082 | 60984 | 85 (2)| 00:00:02 || 5 | TABLE ACCESS FULL | A2 | 10000 | 40000 | 44 (0)| 00:00:01 || 6 | TABLE ACCESS FULL | A1 | 10000 | 80000 | 40 (0)| 00:00:01 ||* 7 | HASH JOIN ANTI | | 26 | 416 | 124 (2)| 00:00:02 ||* 8 | HASH JOIN RIGHT SEMI| | 2587 | 31044 | 79 (2)| 00:00:01 || 9 | TABLE ACCESS FULL | A3 | 8422 | 33688 | 38 (0)| 00:00:01 || 10 | TABLE ACCESS FULL | A1 | 10000 | 80000 | 40 (0)| 00:00:01 || 11 | TABLE ACCESS FULL | A2 | 10000 | 40000 | 44 (0)| 00:00:01 |---------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 4 - access("A2"."OBJECT_ID"="A1"."OBJECT_ID") 7 - access("P"."OBJECT_ID"="A1"."OBJECT_ID") 8 - access("A3"."OBJECT_ID"="A1"."OBJECT_ID")Statistics---------------------------------------------------------- 1 recursive calls 0 db block gets 686 consistent gets 0 physical reads 0 redo size 709 bytes sent via SQL*Net to client 520 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 5 rows processedSQL> SQL> SELECT a1.owner, COUNT (*) 2 FROM dev.a1 3 WHERE EXISTS 4 (SELECT /*+ hash_sj(a1 a2) */ 5 * 6 FROM dev.a2 7 WHERE a2.object_id = a1.object_id) 8 OR EXISTS 9 (SELECT /*+ hash_sj(a1 a2) */ 10 * 11 FROM dev.a3 12 WHERE a3.object_id = a1.object_id) 13 GROUP BY a1.owner;Elapsed: 00:00:00.03Execution Plan----------------------------------------------------------Plan hash value: 3327704572---------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 5 | 60 | 124 (2)| 00:00:02 || 1 | HASH GROUP BY | | 5 | 60 | 124 (2)| 00:00:02 ||* 2 | HASH JOIN SEMI | | 5082 | 60984 | 123 (1)| 00:00:02 || 3 | TABLE ACCESS FULL | A1 | 10000 | 80000 | 40 (0)| 00:00:01 || 4 | VIEW | VW_SQ_1 | 18422 | 73688 | 82 (0)| 00:00:01 || 5 | UNION-ALL | | | | | || 6 | TABLE ACCESS FULL| A3 | 8422 | 33688 | 38 (0)| 00:00:01 || 7 | TABLE ACCESS FULL| A2 | 10000 | 40000 | 44 (0)| 00:00:01 |---------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 2 - access("VW_COL_1"="A1"."OBJECT_ID")Statistics---------------------------------------------------------- 54 recursive calls 0 db block gets 424 consistent gets 1 physical reads 0 redo size 709 bytes sent via SQL*Net to client 520 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 6 sorts (memory) 0 sorts (disk) 5 rows processedSQL> SQL> SQL> /* Formatted on 2013/09/21 14:23:32 (QP5 v5.227.12220.39754) */SQL> SELECT x.owner, COUNT (*) 2 FROM (SELECT * 3 FROM dev.a1 4 WHERE EXISTS 5 (SELECT /*+ hash_sj(a1 a2)*/ 6 * 7 FROM dev.a2 8 WHERE a2.object_id = a1.object_id) 9 UNION ALL 10 SELECT * 11 FROM dev.a1 12 WHERE NOT EXISTS 13 (SELECT /*+ hash_aj(a1 p)*/ 14 * 15 FROM dev.a2 p 16 WHERE p.object_id = a1.object_id) 17 AND EXISTS 18 (SELECT /*+ hash_sj(a1 a3)*/ 19 * 20 FROM dev.a3 21 WHERE a3.object_id = a1.object_id)) x 22 GROUP BY x.owner;Elapsed: 00:00:00.02Execution Plan----------------------------------------------------------Plan hash value: 195072970---------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 5 | 25 | 210 (2)| 00:00:03 || 1 | HASH GROUP BY | | 5 | 25 | 210 (2)| 00:00:03 || 2 | VIEW | | 5108 | 25540 | 209 (2)| 00:00:03 || 3 | UNION-ALL | | | | | ||* 4 | HASH JOIN RIGHT SEMI | | 5082 | 60984 | 85 (2)| 00:00:02 || 5 | TABLE ACCESS FULL | A2 | 10000 | 40000 | 44 (0)| 00:00:01 || 6 | TABLE ACCESS FULL | A1 | 10000 | 80000 | 40 (0)| 00:00:01 ||* 7 | HASH JOIN ANTI | | 26 | 416 | 124 (2)| 00:00:02 ||* 8 | HASH JOIN RIGHT SEMI| | 2587 | 31044 | 79 (2)| 00:00:01 || 9 | TABLE ACCESS FULL | A3 | 8422 | 33688 | 38 (0)| 00:00:01 || 10 | TABLE ACCESS FULL | A1 | 10000 | 80000 | 40 (0)| 00:00:01 || 11 | TABLE ACCESS FULL | A2 | 10000 | 40000 | 44 (0)| 00:00:01 |---------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 4 - access("A2"."OBJECT_ID"="A1"."OBJECT_ID") 7 - access("P"."OBJECT_ID"="A1"."OBJECT_ID") 8 - access("A3"."OBJECT_ID"="A1"."OBJECT_ID")Statistics---------------------------------------------------------- 1 recursive calls 0 db block gets 686 consistent gets 0 physical reads 0 redo size 709 bytes sent via SQL*Net to client 520 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 5 rows processedSQL> 如果子句中含有group by这种排序操作,使用in来代替exists操作会大大提高效率,示例如下:修改一下示例表:SQL> insert into dev.a2 select * from dev.a2;SQL> commit;使用exists操作,无论添加什么提示都不能使其走semi-join,耗费大量时间SQL> set linesize 177SQL> set timing onSQL> set autotrace onSQL> /* Formatted on 2013/09/21 14:40:50 (QP5 v5.227.12220.39754) */SQL> SELECT COUNT (*) 2 FROM dev.a1 a 3 WHERE EXISTS 4 (SELECT /*+ hash_sj(a b) */ 5 * 6 FROM ( SELECT object_id 7 FROM dev.a2 8 GROUP BY object_id 9 HAVING COUNT (*) > 1) b 10 WHERE a.object_id = b.object_id); COUNT(*)---------- 5000Elapsed: 00:00:16.13Execution Plan----------------------------------------------------------Plan hash value: 1410689026--------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 3 | 220K (1)| 00:44:12 || 1 | SORT AGGREGATE | | 1 | 3 | | ||* 2 | FILTER | | | | | || 3 | TABLE ACCESS FULL | A1 | 10000 | 30000 | 40 (0)| 00:00:01 ||* 4 | FILTER | | | | | || 5 | SORT GROUP BY NOSORT| | 1 | 4 | 44 (0)| 00:00:01 ||* 6 | TABLE ACCESS FULL | A2 | 1 | 4 | 44 (0)| 00:00:01 |--------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 2 - filter( EXISTS (SELECT 0 FROM "DEV"."A2" "A2" WHERE "OBJECT_ID"=:B1 GROUP BY "OBJECT_ID" HAVING COUNT(*)>1)) 4 - filter(COUNT(*)>1) 6 - filter("OBJECT_ID"=:B1)Statistics---------------------------------------------------------- 0 recursive calls 10000 db block gets 3190133 consistent gets 0 physical reads 0 redo size 526 bytes sent via SQL*Net to client 520 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processedSQL> 将exists改为in句型,就可以用到semi-join,效率大大提高SQL> /* Formatted on 2013/09/21 14:45:40 (QP5 v5.227.12220.39754) */SQL> SELECT COUNT (*) 2 FROM dev.a1 a 3 WHERE object_id IN ( SELECT object_id 4 FROM dev.a2 b 5 GROUP BY object_id 6 HAVING COUNT (*) > 1); COUNT(*)---------- 5000Elapsed: 00:00:00.02Execution Plan----------------------------------------------------------Plan hash value: 3434654636-----------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 16 | 86 (3)| 00:00:02 || 1 | SORT AGGREGATE | | 1 | 16 | | ||* 2 | HASH JOIN RIGHT SEMI | | 500 | 8000 | 86 (3)| 00:00:02 || 3 | VIEW | VW_NSO_1 | 500 | 6500 | 45 (3)| 00:00:01 ||* 4 | FILTER | | | | | || 5 | HASH GROUP BY | | 25 | 2000 | 45 (3)| 00:00:01 || 6 | TABLE ACCESS FULL| A2 | 10000 | 40000 | 44 (0)| 00:00:01 || 7 | TABLE ACCESS FULL | A1 | 10000 | 30000 | 40 (0)| 00:00:01 |-----------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 2 - access("OBJECT_ID"="OBJECT_ID") 4 - filter(COUNT(*)>1)Statistics---------------------------------------------------------- 2 recursive calls 1 db block gets 454 consistent gets 0 physical reads 0 redo size 526 bytes sent via SQL*Net to client 520 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processedSQL>