走FILTER效率高的2种情况

FILTER的适用范围:
1. 主表返回的记录数较少

2.子查询返回记录数较小
下面做实验证明:
select department_name
  from hr.dept_1 dept
 where department_id IN (select department_id from hr.employees_1 emp);

SQL>  select count(*) from dept_1;

  COUNT(*)
----------
	 2

SQL>  select count(*) from employees_1;

  COUNT(*)
----------
   3506176

SQL> select department_name
  from hr.dept_1 dept
 where department_id IN (select department_id from hr.employees_1 emp);  2    3  


Execution Plan
----------------------------------------------------------
Plan hash value: 3257593059

---------------------------------------------------------------------------------------
| Id  | Operation	   | Name	      | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |		      |     2 |    40 |     7	(0)| 00:00:01 |
|   1 |  NESTED LOOPS SEMI |		      |     2 |    40 |     7	(0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPT_1	      |     2 |    32 |     3	(0)| 00:00:01 |
|*  3 |   INDEX RANGE SCAN | EMPLOYEES_1_IDX1 |  3508K|    13M|     2	(0)| 00:00:01 |
---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("DEPARTMENT_ID"="DEPARTMENT_ID")


Statistics
----------------------------------------------------------
	  0  recursive calls
	  0  db block gets
	 10  consistent gets
	  0  physical reads
	  0  redo size
	486  bytes sent via SQL*Net to client
	419  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	  0  sorts (memory)
	  0  sorts (disk)
	  2  rows processed


那么走FILTER呢?
SQL> select department_name
  from hr.dept_1 dept
 where department_id IN (select /*+ NO_UNNEST */ department_id from hr.employees_1 emp);  2    3  


Execution Plan
----------------------------------------------------------
Plan hash value: 1766326341

---------------------------------------------------------------------------------------
| Id  | Operation	   | Name	      | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |		      |     1 |    16 |     6	(0)| 00:00:01 |
|*  1 |  FILTER 	   |		      |       |       | 	   |	      |
|   2 |   TABLE ACCESS FULL| DEPT_1	      |     2 |    32 |     3	(0)| 00:00:01 |
|*  3 |   INDEX RANGE SCAN | EMPLOYEES_1_IDX1 |     2 |     8 |     3	(0)| 00:00:01 |
---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "HR"."EMPLOYEES_1" "EMP"
	      WHERE "DEPARTMENT_ID"=:B1))
   3 - access("DEPARTMENT_ID"=:B1)


Statistics
----------------------------------------------------------
	  0  recursive calls
	  0  db block gets
	 10  consistent gets
	  0  physical reads
	  0  redo size
	486  bytes sent via SQL*Net to client
	419  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	  0  sorts (memory)
	  0  sorts (disk)
	  2  rows processed



此时效率一样,说明当from ...主表 返回数据 只返回几条 走FILTER没问题(主表小是之返回行数少)


那么还有什么情况,可以走FILTER呢?

SQL>  select * from test a where object_id in (select   department_id
  from hr.dept_1 dept
 where department_id IN (select   department_id from hr.employees_1 emp));  2    3  

64 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 717021958

--------------------------------------------------------------------------------------------
| Id  | Operation		| Name		   | Rows  | Bytes | Cost (%CPU)| Time	   |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT	|		   |	 1 |   207 |  9747   (7)| 00:01:57 |
|   1 |  VIEW			| VM_NWVW_2	   |	 1 |   207 |  9747   (7)| 00:01:57 |
|   2 |   HASH UNIQUE		|		   |	 1 |   226 |  9747   (7)| 00:01:57 |
|*  3 |    HASH JOIN		|		   |	14M|  3134M|  9264   (2)| 00:01:52 |
|*  4 |     HASH JOIN		|		   |	46 | 10212 |  7400   (1)| 00:01:29 |
|   5 |      TABLE ACCESS FULL	| DEPT_1	   |	 2 |	 6 |	 3   (0)| 00:00:01 |
|   6 |      TABLE ACCESS FULL	| TEST		   |  2511K|   524M|  7389   (1)| 00:01:29 |
|   7 |     INDEX FAST FULL SCAN| EMPLOYEES_1_IDX1 |  3508K|	13M|  1819   (1)| 00:00:22 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("DEPARTMENT_ID"="DEPARTMENT_ID")
   4 - access("OBJECT_ID"="DEPARTMENT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
	  0  recursive calls
	  0  db block gets
      57221  consistent gets
      41372  physical reads
	  0  redo size
       2850  bytes sent via SQL*Net to client
	463  bytes received via SQL*Net from client
	  6  SQL*Net roundtrips to/from client
	  0  sorts (memory)
	  0  sorts (disk)
	 64  rows processed


这里子查询被展开了,导致test和dept_1先关联了,但是子查询
SQL> (select   department_id
  from hr.dept_1 dept
 where department_id IN (select   department_id from hr.employees_1 emp))  2    3  ;

DEPARTMENT_ID
-------------
	   10
	   20
只返回了2条记录,可以让它走FILTER。

SQL> select * from test a where object_id in (select  department_id
  from hr.dept_1 dept
 where department_id IN (select /*+ NO_UNNEST */  department_id from hr.employees_1 emp));  2    3  

64 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1506439343

-----------------------------------------------------------------------------------------
| Id  | Operation	     | Name		| Rows	| Bytes | Cost (%CPU)| Time	|
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |			|    23 |  5060 |  7403   (1)| 00:01:29 |
|*  1 |  HASH JOIN RIGHT SEMI|			|    23 |  5060 |  7403   (1)| 00:01:29 |
|   2 |   VIEW		     | VW_NSO_1 	|     1 |    13 |     6   (0)| 00:00:01 |
|*  3 |    FILTER	     |			|	|	|	     |		|
|   4 |     TABLE ACCESS FULL| DEPT_1		|     2 |     6 |     3   (0)| 00:00:01 |
|*  5 |     INDEX RANGE SCAN | EMPLOYEES_1_IDX1 |     2 |     8 |     3   (0)| 00:00:01 |
|   6 |   TABLE ACCESS FULL  | TEST		|  2511K|   495M|  7389   (1)| 00:01:29 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("OBJECT_ID"="DEPARTMENT_ID")
   3 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "HR"."EMPLOYEES_1" "EMP"
	      WHERE "DEPARTMENT_ID"=:B1))
   5 - access("DEPARTMENT_ID"=:B1)

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
	  0  recursive calls
	  0  db block gets
      48871  consistent gets
      33065  physical reads
	  0  redo size
       4119  bytes sent via SQL*Net to client
	463  bytes received via SQL*Net from client
	  6  SQL*Net roundtrips to/from client
	  0  sorts (memory)
	  0  sorts (disk)
	 64  rows processed

走FILTER后逻辑读下降到了 48871 。

总结如果子查询返回数据很少,那么不妨让它走filter,这种情况如果子查询被展开,那么会导致执行计划混乱,导致大表先和子查询里的大表关联。












原文地址:https://www.cnblogs.com/zhaoyangjian724/p/3798012.html