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,这种情况如果子查询被展开,那么会导致执行计划混乱,导致大表先和子查询里的大表关联。