VW_NSO_1 我們查看執行計劃的時候動態創建的,VM 是ORACLE視圖的約定前綴/後綴,在和老外工作的時候,經常可以看到有VW的後綴,它就表示視圖,這是習慣。
下面就是某日用品行業老大某某數據倉庫的視圖,它的後綴是VW
SQL> select view_name from dba_views where view_name like '%VW%';
VIEW_NAME
------------------------------------------------------------
GPOS_MDGC_TSC_ADL_VW
GPOS_MDGC_TSC_STORE_GRP_VW
GPOS_LLCA02_FACT_NT_SPEC_VW
GPOS_LLCA_ADL_VW
GPOS_LLCA_STORE_GRP_VW
GPOS_LLCA_AZ_FACT_VW
GPOS_RODE03_FACT_NATL_SPEC_VW
.....................................................................省略......................................................................
NSO 可以這樣理解:nested subquery optimizing ,把in轉換爲JOIN,把NOT IN轉換爲 anti join(如果能確保列不爲null)
那麼什麼時候oracle會生成 VW_NSO_1 這樣的視圖呢,請看下面的幾個例子(基於ORACLE10g):
SQL> select count(*) from t1 where object_id not in (select MAX(object_id) from t2 GROUP BY OWNER);
已用時間: 00: 00: 00.05
執行計劃
----------------------------------------------------------
Plan hash value: 350791718
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 32 (13)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 18 | | |
|* 2 | HASH JOIN RIGHT ANTI | | 51176 | 899K| 32 (13)| 00:00:01 |
| 3 | VIEW | VW_NSO_1 | 1 | 13 | 3 (34)| 00:00:01 |
| 4 | HASH GROUP BY | | 1 | 30 | 3 (34)| 00:00:01 |
| 5 | TABLE ACCESS FULL | T2 | 1 | 30 | 2 (0)| 00:00:01 |
| 6 | INDEX FAST FULL SCAN| T1_ID | 51177 | 249K| 27 (4)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"="$nso_col_1")
SQL> select count(*) from t1 where object_id not in (select MAX(object_id) from t2 );
已用時間: 00: 00: 00.01
執行計劃
----------------------------------------------------------
Plan hash value: 4201411252
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 29 (7)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
|* 2 | INDEX FAST FULL SCAN | T1_ID | 51176 | 249K| 28 (8)| 00:00:01 |
| 3 | SORT AGGREGATE | | 1 | 13 | | |
| 4 | INDEX FULL SCAN (MIN/MAX)| T2_ID | 1 | 13 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_ID"<> (SELECT MAX("OBJECT_ID") FROM "T2" "T2"))
SQL> select count(*) from t1 where object_id in (select object_id from t2 where rownum=10);
已用時間: 00: 00: 00.00
執行計劃
----------------------------------------------------------
Plan hash value: 3285035028
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 2 (50)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 18 | | |
| 2 | NESTED LOOPS | | 1 | 18 | 2 (50)| 00:00:01 |
| 3 | VIEW | VW_NSO_1 | 1 | 13 | 0 (0)| 00:00:01 |
| 4 | HASH UNIQUE | | 1 | 13 | | |
| 5 | COUNT | | | | | |
|* 6 | FILTER | | | | | |
| 7 | INDEX FULL SCAN| T2_ID | 1 | 13 | 0 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | T1_ID | 1 | 5 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - filter(ROWNUM=10)
8 - access("OBJECT_ID"="$nso_col_1")
SQL> select count(*) from t1 where object_id in (select object_id from t2 where owner='SYS' UNION ALL select object_id from test where owner='SCOTT');
已用時間: 00: 00: 00.06
執行計劃
----------------------------------------------------------
Plan hash value: 3457113806
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 34 (9)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 18 | | |
|* 2 | HASH JOIN | | 140 | 2520 | 34 (9)| 00:00:01 |
| 3 | VIEW | VW_NSO_1 | 137 | 1781 | 5 (0)| 00:00:01 |
| 4 | HASH UNIQUE | | 137 | 1526 | 5 (60)| 00:00:01 |
| 5 | UNION-ALL | | | | | |
|* 6 | TABLE ACCESS FULL| T2 | 1 | 30 | 2 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | XXX | 136 | 1496 | 3 (0)| 00:00:01 |
| 8 | INDEX FAST FULL SCAN| T1_ID | 51177 | 249K| 27 (4)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"="$nso_col_1")
6 - filter("OWNER"='SYS')
7 - access("OWNER"='SCOTT')
SQL> select count(*) from t1 where object_id in (select object_id from t2 where owner='SYS' minus select object_id from test where owner='SCOTT');
已用時間: 00: 00: 00.03
執行計劃
----------------------------------------------------------
Plan hash value: 182265946
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 8 (25)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 18 | | |
| 2 | NESTED LOOPS | | 1 | 18 | 8 (25)| 00:00:01 |
| 3 | VIEW | VW_NSO_1 | 1 | 13 | 7 (29)| 00:00:01 |
| 4 | MINUS | | | | | |
| 5 | SORT UNIQUE | | 1 | 30 | | |
|* 6 | TABLE ACCESS FULL| T2 | 1 | 30 | 2 (0)| 00:00:01 |
| 7 | SORT UNIQUE | | 136 | 1496 | | |
|* 8 | INDEX RANGE SCAN | XXX | 136 | 1496 | 3 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | T1_ID | 1 | 5 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - filter("OWNER"='SYS')
8 - access("OWNER"='SCOTT')
9 - access("OBJECT_ID"="$nso_col_1")
SQL> select count(*) from t1 where object_id in (SELECT LEVEL FROM DUAL CONNECT BY LEVEL<100);
已用時間: 00: 00: 00.05
執行計劃
----------------------------------------------------------
Plan hash value: 1672622903
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 4 (25)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 18 | | |
| 2 | NESTED LOOPS | | 1 | 18 | 4 (25)| 00:00:01 |
| 3 | VIEW | VW_NSO_1 | 1 | 13 | 3 (34)| 00:00:01 |
| 4 | HASH UNIQUE | | 1 | | 3 (34)| 00:00:01 |
|* 5 | CONNECT BY WITHOUT FILTERING| | | | | |
| 6 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | T1_ID | 1 | 5 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - filter(LEVEL<100)
7 - access("OBJECT_ID"="$nso_col_1")
看到了吧,當子查詢裏面有 (max/min/avg,group by), rownum, UNION,UNION ALL,INTERSECT,MINUS,connect by ...start with ,
ORACLE會將子查詢轉換爲視圖VW_NSO_x,其實這些限制也是VIEW MERGE的限制,當一個視圖中有上面的條件,ORACLE就無法對視圖進行merge。
如果你不想CBO生成VW_NSO_1,你只需要在子查詢裏面加上hint NO_UNNEST 即可,這時候CBO就會走FILTER。