当 SQL 语句中同时有 or 和子查询,这种情况下子查询无法展开(unnest),只能走 FILTER。遇到这种情况我们可以将 SQL 改写为 union,从而消除 FILTER。
带有 or 子查询的写法与执行计划如下。
select *from t1where owner = 'SCOTT'or object_id in (select object_id from t2);
72571 rows selected.Execution Plan----------------------------------------------------------Plan hash value: 895956251---------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 3378 | 682K| 235 (1)| 00:00:03 ||* 1 | FILTER | | | | | || 2 | TABLE ACCESS FULL| T1 | 56766 | 11M| 235 (1)| 00:00:03 ||* 3 | TABLE ACCESS FULL| T2 | 734 | 9542 | 2 (0)| 00:00:01 |---------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------1 - filter("OWNER"='SCOTT' OR EXISTS (SELECT 0 FROM "T2" "T2" WHERE"OBJECT_ID"=:B1))3 - filter("OBJECT_ID"=:B1)
改写为 union 的写法如下。
select * from t1 where owner='SCOTT'unionselect * from t1 where object_id in(select object_id from t2);
72571 rows selected.Execution Plan----------------------------------------------------------Plan hash value: 696035008--------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)|--------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 56778 | 11M| | 4088 (95)|| 1 | SORT UNIQUE | | 56778 | 11M| 12M| 4088 (95)|| 2 | UNION-ALL | | | | | ||* 3 | TABLE ACCESS FULL | T1 | 12 | 2484 | | 234 (1)||* 4 | HASH JOIN | | 56766 | 11M| 1800K| 1146 (1)|| 5 | TABLE ACCESS FULL| T2 | 73407 | 931K| | 234 (1)|| 6 | TABLE ACCESS FULL| T1 | 56766 | 11M| | 235 (1)|--------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------3 - filter("OWNER"='SCOTT')4 - access("OBJECT_ID"="OBJECT_ID")
改写为 union 之后,消除了 FILTER。如果无法改写 SQL,那么 SQL 就只能走 FILTER,这时我们需要在子查询表的连接列(t2.object_id)建立索引。
