[20140823]12c join convert連線轉換.txt

lfree發表於2014-08-25

[20140823]12c join convert連線轉換.txt

--前面提高12c執行計劃的Partial Join Evaluation.現在看看12c join convert.
--連結:

1.建立測試環境:

SCOTT@test01p> @ver
BANNER                                                                               CON_ID
-------------------------------------------------------------------------------- ----------
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production              0

create table t1 as select rownum id ,cast('testtest' as varchar2(10)) name from dual connect by level<=1e5;
create table t2 as select rownum id ,cast('testtest' as varchar2(10)) name from dual connect by level<=10;
create unique index pk_t1 on t1 (id);
alter table t1 add constraint pk_t1 primary key (id);
create unique index pk_t2 on t2 (id);
alter table t2 add constraint pk_t2 primary key (id);
execute dbms_stats.gather_table_stats(user,'t1',cascade=>true,method_opt=>'for all columns size 1',no_invalidate=>false);
execute dbms_stats.gather_table_stats(user,'t2',cascade=>true,method_opt=>'for all columns size 1',no_invalidate=>false);

SYS@test01p> @hide _convert_set_to_join
NAME                  DESCRIPTION                                 DEFAULT_VALUE  SESSION_VALUE  SYSTEM_VALUE
--------------------- ------------------------------------------- -------------- -------------- ------------
_convert_set_to_join  enables conversion of set operator to join  TRUE           FALSE          FALSE
--12.1.0.1版本_convert_set_to_join=false.

2.測試:
SCOTT@test01p> alter session set statistics_level=all;
Session altered.
SCOTT@test01p> select * from t1 intersect select * from t2;
ID NAME
--- ---------
  1 testtest
  2 testtest
  3 testtest
  4 testtest
  5 testtest
  6 testtest
  7 testtest
  8 testtest
  9 testtest
10 testtest
10 rows selected.

SCOTT@test01p> @dpc '' outline
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  g5jv20wwdh1zz, child number 0
-------------------------------------
select * from t1 intersect select * from t2
Plan hash value: 1917753433
------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |   576 (100)|     10 |00:00:00.08 |     269 |       |       |          |
|   1 |  INTERSECTION       |      |      1 |        |            |     10 |00:00:00.08 |     269 |       |       |          |
|   2 |   SORT UNIQUE       |      |      1 |    100K|   573   (1)|    100K|00:00:00.07 |     266 |  5510K|   963K| 4897K (0)|
|   3 |    TABLE ACCESS FULL| T1   |      1 |    100K|    77   (0)|    100K|00:00:00.01 |     266 |       |       |          |
|   4 |   SORT UNIQUE       |      |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       3 |  2048 |  2048 | 2048  (0)|
|   5 |    TABLE ACCESS FULL| T2   |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       3 |       |       |          |
------------------------------------------------------------------------------------------------------------------------------
Outline Data
-------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('12.1.0.1')
      DB_VERSION('12.1.0.1')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      OUTLINE_LEAF(@"SEL$2")
      OUTLINE_LEAF(@"SET$1")
      FULL(@"SEL$2" "T2"@"SEL$2")
      FULL(@"SEL$1" "T1"@"SEL$1")
      END_OUTLINE_DATA
  */

--可以發現執行出現INTERSECTION,與一些11g版本一樣.Buffers=269.

SCOTT@test01p> select /*+ SET_TO_JOIN(@"SET$1") */ * from t1 intersect select * from t2;
ID NAME
-- --------------------
7 testtest
8 testtest
2 testtest
5 testtest
1 testtest
3 testtest
6 testtest
10 testtest
4 testtest
9 testtest

--注意輸出的順序發生了一些"混亂",對比前面的輸出.

SCOTT@test01p> @dpc '' outline
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  7y6uhq1r2bhnr, child number 0
-------------------------------------
select /*+ SET_TO_JOIN(@"SET$1") */ * from t1 intersect select * from t2
Plan hash value: 847386728
-----------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name  | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |       |      1 |        |    13 (100)|     10 |00:00:00.01 |      13 |       |       |          |
|   1 |  HASH UNIQUE                  |       |      1 |     10 |    13   (0)|     10 |00:00:00.01 |      13 |  1600K|  1600K|  979K (0)|
|   2 |   NESTED LOOPS                |       |      1 |        |            |     10 |00:00:00.01 |      13 |       |       |          |
|   3 |    NESTED LOOPS               |       |      1 |     10 |    13   (0)|     10 |00:00:00.01 |      12 |       |       |          |
|   4 |     TABLE ACCESS FULL         | T2    |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       3 |       |       |          |
|*  5 |     INDEX UNIQUE SCAN         | PK_T1 |     10 |      1 |     0   (0)|     10 |00:00:00.01 |       9 |       |       |          |
|*  6 |    TABLE ACCESS BY INDEX ROWID| T1    |     10 |      1 |     1   (0)|     10 |00:00:00.01 |       1 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------
Outline Data
-------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('12.1.0.1')
      DB_VERSION('12.1.0.1')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$02B15F54")
      MERGE(@"SEL$1")
      MERGE(@"SEL$2")
      OUTLINE(@"SET$09AAA538")
      SET_TO_JOIN(@"SET$1")
      ~~~~~~~~~~~~~~~~~~~~~
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      OUTLINE(@"SET$1")
      FULL(@"SEL$02B15F54" "T2"@"SEL$2")
      INDEX(@"SEL$02B15F54" "T1"@"SEL$1" ("T1"."ID"))
      LEADING(@"SEL$02B15F54" "T2"@"SEL$2" "T1"@"SEL$1")
      USE_NL(@"SEL$02B15F54" "T1"@"SEL$1")
      NLJ_BATCHING(@"SEL$02B15F54" "T1"@"SEL$1")
      USE_HASH_AGGREGATION(@"SEL$02B15F54")
      END_OUTLINE_DATA
  */
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("T1"."ID"="T2"."ID")
   6 - filter(SYS_OP_MAP_NONNULL("T1"."NAME")=SYS_OP_MAP_NONNULL("T2"."NAME"))
Note
-----
   - this is an adaptive plan

--可以發現幾點變化:
1.執行計劃沒有出現INTERSECTION,而是轉化為join操作.
2.另外一個副作用這個執行計劃adaptive plan,後面再看看為什麼?
3.buffer=13,比原來大大減少.操作先掃描T2小表.在連線T1,邏輯讀自然大大減少.
4.看不明白,為什麼輸出的順序會發生變化.....?????也許出在執行計劃的HASH UNIQUE上.

3.使用提示看看:
SCOTT@test01p> select /*+ OPT_PARAM('_convert_set_to_join' 'true') */ * from t1 intersect select * from t2;
ID NAME
-- --------------------
7 testtest
8 testtest
2 testtest
5 testtest
1 testtest
3 testtest
6 testtest
10 testtest
4 testtest
9 testtest
10 rows selected.
--執行計劃與select /*+ SET_TO_JOIN(@"SET$1") */ * from t1 intersect select * from t2一樣,不再貼出.

4.修改引數測試:
--我使用的12.1.0.1.0版本._convert_set_to_join=false.設定為true看看.
SCOTT@test01p> alter session set "_convert_set_to_join"=true ;
Session altered.

SCOTT@test01p> select * from t1 intersect select * from t2;
ID NAME
-- --------------------
7 testtest
8 testtest
2 testtest
5 testtest
1 testtest
3 testtest
6 testtest
10 testtest
4 testtest
9 testtest
10 rows selected.

--執行計劃與select /*+ SET_TO_JOIN(@"SET$1") */ * from t1 intersect select * from t2一樣,不在貼出.

5.看看是否順序可以改變:
SCOTT@test01p> select * from V$SQL_HINT where name like '%USE%AGGREGATION%';
NAME                    SQL_FEATURE          CLASS                 INVERSE                  TARGET_LEVEL   PROPERTY VERSION    VERSION_OUTLINE CON_ID
----------------------- -------------------- --------------------- ------------------------ ------------ ---------- ---------- --------------- ------
USE_HASH_AGGREGATION    QKSFM_ALL            USE_HASH_AGGREGATION  NO_USE_HASH_AGGREGATION             2          0 10.2.0.1   10.2.0.5             0
NO_USE_HASH_AGGREGATION QKSFM_ALL            USE_HASH_AGGREGATION  USE_HASH_AGGREGATION                2          0 10.2.0.1   10.2.0.5             0
--猜測換成NO_USE_HASH_AGGREGATION看看.

select
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('12.1.0.1')
      DB_VERSION('12.1.0.1')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$02B15F54")
      MERGE(@"SEL$1")
      MERGE(@"SEL$2")
      OUTLINE(@"SET$09AAA538")
      SET_TO_JOIN(@"SET$1")
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      OUTLINE(@"SET$1")
      FULL(@"SEL$02B15F54" "T2"@"SEL$2")
      INDEX(@"SEL$02B15F54" "T1"@"SEL$1" ("T1"."ID"))
      LEADING(@"SEL$02B15F54" "T2"@"SEL$2" "T1"@"SEL$1")
      USE_NL(@"SEL$02B15F54" "T1"@"SEL$1")
      NLJ_BATCHING(@"SEL$02B15F54" "T1"@"SEL$1")
      NO_USE_HASH_AGGREGATION(@"SEL$02B15F54")
      END_OUTLINE_DATA
  */ * from t1 intersect select * from t2;

ID NAME
-- --------------------
1 testtest
2 testtest
3 testtest
4 testtest
5 testtest
6 testtest
7 testtest
8 testtest
9 testtest
10 testtest
10 rows selected.

SCOTT@test01p> @dpc '' outline
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  3frmt98v3kjsp, child number 0
-------------------------------------
select   /*+       BEGIN_OUTLINE_DATA       IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('12.1.0.1')
DB_VERSION('12.1.0.1')       ALL_ROWS
OUTLINE_LEAF(@"SEL$02B15F54")       MERGE(@"SEL$1")
MERGE(@"SEL$2")       OUTLINE(@"SET$09AAA538")
SET_TO_JOIN(@"SET$1")       OUTLINE(@"SEL$1")       OUTLINE(@"SEL$2")
    OUTLINE(@"SET$1")       FULL(@"SEL$02B15F54" "T2"@"SEL$2")
INDEX(@"SEL$02B15F54" "T1"@"SEL$1" ("T1"."ID"))
LEADING(@"SEL$02B15F54" "T2"@"SEL$2" "T1"@"SEL$1")
USE_NL(@"SEL$02B15F54" "T1"@"SEL$1")       NLJ_BATCHING(@"SEL$02B15F54"
"T1"@"SEL$1")       NO_USE_HASH_AGGREGATION(@"SEL$02B15F54")
END_OUTLINE_DATA   */ * from t1 intersect select * from t2

Plan hash value: 1438968633

-----------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name  | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |       |      1 |        |    13 (100)|     10 |00:00:00.01 |      13 |       |       |          |
|   1 |  SORT UNIQUE                  |       |      1 |      8 |    13   (0)|     10 |00:00:00.01 |      13 |  2048 |  2048 | 2048  (0)|
|   2 |   NESTED LOOPS                |       |      1 |        |            |     10 |00:00:00.01 |      13 |       |       |          |
|   3 |    NESTED LOOPS               |       |      1 |     10 |    13   (0)|     10 |00:00:00.01 |      12 |       |       |          |
|   4 |     TABLE ACCESS FULL         | T2    |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       3 |       |       |          |
|*  5 |     INDEX UNIQUE SCAN         | PK_T1 |     10 |      1 |     0   (0)|     10 |00:00:00.01 |       9 |       |       |          |
|*  6 |    TABLE ACCESS BY INDEX ROWID| T1    |     10 |      1 |     1   (0)|     10 |00:00:00.01 |       1 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------
Outline Data
-------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('12.1.0.1')
      DB_VERSION('12.1.0.1')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$02B15F54")
      MERGE(@"SEL$1")
      MERGE(@"SEL$2")
      OUTLINE(@"SET$09AAA538")
      SET_TO_JOIN(@"SET$1")
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      OUTLINE(@"SET$1")
      FULL(@"SEL$02B15F54" "T2"@"SEL$2")
      INDEX(@"SEL$02B15F54" "T1"@"SEL$1" ("T1"."ID"))
      LEADING(@"SEL$02B15F54" "T2"@"SEL$2" "T1"@"SEL$1")
      USE_NL(@"SEL$02B15F54" "T1"@"SEL$1")
      NLJ_BATCHING(@"SEL$02B15F54" "T1"@"SEL$1")
      END_OUTLINE_DATA
  */
Predicate Information (identified by operation id):
---------------------------------------------------
   5 - access("T1"."ID"="T2"."ID")
   6 - filter(SYS_OP_MAP_NONNULL("T1"."NAME")=SYS_OP_MAP_NONNULL("T2"."NAME"))
60 rows selected.

6.最後觀察為什麼出現adaptive plan.

--重新進入:
SCOTT@test01p> alter session set statistics_level=all;
Session altered.

select /*+ SET_TO_JOIN(@"SET$1") */ * from t1 intersect select * from t2;

SCOTT@test01p> @dpc '' outline,adaptive
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  7y6uhq1r2bhnr, child number 2
-------------------------------------
select /*+ SET_TO_JOIN(@"SET$1") */ * from t1 intersect select * from t2

Plan hash value: 847386728

--------------------------------------------------------------------------------------------------------------------------------------------
|   Id  | Operation                      | Name  | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------
|     0 | SELECT STATEMENT               |       |      1 |        |    13 (100)|     10 |00:00:00.01 |      13 |       |       |          |
|     1 |  HASH UNIQUE                   |       |      1 |      1 |    13   (0)|     10 |00:00:00.01 |      13 |  1600K|  1600K|  985K (0)|
|- *  2 |   HASH JOIN                    |       |      1 |      1 |    13   (0)|     10 |00:00:00.01 |      13 |  1079K|  1079K|          |
|     3 |    NESTED LOOPS                |       |      1 |        |            |     10 |00:00:00.01 |      13 |       |       |          |
|     4 |     NESTED LOOPS               |       |      1 |      1 |    13   (0)|     10 |00:00:00.01 |      12 |       |       |          |
|-    5 |      STATISTICS COLLECTOR      |       |      1 |        |            |     10 |00:00:00.01 |       3 |       |       |          |
|     6 |       TABLE ACCESS FULL        | T2    |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       3 |       |       |          |
|  *  7 |      INDEX UNIQUE SCAN         | PK_T1 |     10 |      1 |     0   (0)|     10 |00:00:00.01 |       9 |       |       |          |
|  *  8 |     TABLE ACCESS BY INDEX ROWID| T1    |     10 |      1 |     1   (0)|     10 |00:00:00.01 |       1 |       |       |          |
|-    9 |    TABLE ACCESS FULL           | T1    |      0 |      1 |     1   (0)|      0 |00:00:00.01 |       0 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------------------------
Outline Data
-------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('12.1.0.1')
      DB_VERSION('12.1.0.1')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$02B15F54")
      MERGE(@"SEL$1")
      MERGE(@"SEL$2")
      OUTLINE(@"SET$09AAA538")
      SET_TO_JOIN(@"SET$1")
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      OUTLINE(@"SET$1")
      FULL(@"SEL$02B15F54" "T2"@"SEL$2")
      INDEX(@"SEL$02B15F54" "T1"@"SEL$1" ("T1"."ID"))
      LEADING(@"SEL$02B15F54" "T2"@"SEL$2" "T1"@"SEL$1")
      USE_NL(@"SEL$02B15F54" "T1"@"SEL$1")
      NLJ_BATCHING(@"SEL$02B15F54" "T1"@"SEL$1")
      USE_HASH_AGGREGATION(@"SEL$02B15F54")
      END_OUTLINE_DATA
  */
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("T1"."ID"="T2"."ID" AND SYS_OP_MAP_NONNULL("T1"."NAME")=SYS_OP_MAP_NONNULL("T2"."NAME"))
   7 - access("T1"."ID"="T2"."ID")
Note
-----
   - statistics feedback used for this statement
   - this is an adaptive plan (rows marked '-' are inactive)
59 rows selected.
--對adaptive plan不是很熟悉,可以理解marked '-' are inactive.或者先生成的是這些帶-,實際執行時發生了改變.


7.再回頭看看原始的執行計劃:
SCOTT@test01p> @dpc '' outline
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  g5jv20wwdh1zz, child number 0
-------------------------------------
select * from t1 intersect select * from t2
Plan hash value: 1917753433
------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |   576 (100)|     10 |00:00:00.08 |     269 |       |       |          |
|   1 |  INTERSECTION       |      |      1 |        |            |     10 |00:00:00.08 |     269 |       |       |          |
|   2 |   SORT UNIQUE       |      |      1 |    100K|   573   (1)|    100K|00:00:00.07 |     266 |  5510K|   963K| 4897K (0)|
|   3 |    TABLE ACCESS FULL| T1   |      1 |    100K|    77   (0)|    100K|00:00:00.01 |     266 |       |       |          |
|   4 |   SORT UNIQUE       |      |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       3 |  2048 |  2048 | 2048  (0)|
|   5 |    TABLE ACCESS FULL| T2   |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       3 |       |       |          |
------------------------------------------------------------------------------------------------------------------------------

--即使我們建立每個表上都建立了主鍵(欄位id),而老的方法選擇的仍然是全表掃描,每條記錄肯定唯一,而在選擇sort unique有點多餘.
--即使寫成如下:
select id from t1 intersect select id from t2;
--執行計劃如下,依舊出現SORT UNIQUE.buffers=218 , 也不小.
-------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name  | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |       |      1 |        |   365 (100)|     10 |00:00:00.10 |     218 |      2 |       |       |          |
|   1 |  INTERSECTION          |       |      1 |        |            |     10 |00:00:00.10 |     218 |      2 |       |       |          |
|   2 |   SORT UNIQUE          |       |      1 |    100K|   364   (1)|    100K|00:00:00.09 |     216 |      1 |  4588K|   893K| 4078K (0)|
|   3 |    INDEX FAST FULL SCAN| PK_T1 |      1 |    100K|    58   (0)|    100K|00:00:00.04 |     216 |      1 |       |       |          |
|   4 |   SORT UNIQUE NOSORT   |       |      1 |     10 |     1   (0)|     10 |00:00:00.01 |       2 |      1 |       |       |          |
|   5 |    INDEX FULL SCAN     | PK_T2 |      1 |     10 |     1   (0)|     10 |00:00:00.01 |       2 |      1 |       |       |          |
-------------------------------------------------------------------------------------------------------------------------------------------

--實際上寫成這樣,輸出結果一樣.

select id,name from t2 where (id,name) in ( select id,name from t1);
select id,name from t1 where (id,name) in ( select id,name from t2);

--僅僅貼出第二個執行計劃.實際上如果看Plan hash value是一樣的.
SCOTT@test01p> select id,name from t1 where (id,name) in ( select id,name from t2);
        ID NAME
---------- --------------------
         1 testtest
         2 testtest
         3 testtest
         4 testtest
         5 testtest
         6 testtest
         7 testtest
         8 testtest
         9 testtest
        10 testtest
10 rows selected.

SCOTT@test01p> @dpc '' outline,adaptive
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  dnk2d8zxsk4gf, child number 0
-------------------------------------
select id,name from t1 where (id,name) in ( select id,name from t2)
Plan hash value: 4001747048
----------------------------------------------------------------------------------------------------------------
|   Id  | Operation                     | Name  | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------------------
|     0 | SELECT STATEMENT              |       |      1 |        |    13 (100)|     10 |00:00:00.01 |      23 |
|- *  1 |  HASH JOIN                    |       |      1 |     10 |    13   (0)|     10 |00:00:00.01 |      23 |
|     2 |   NESTED LOOPS                |       |      1 |        |            |     10 |00:00:00.01 |      23 |
|     3 |    NESTED LOOPS               |       |      1 |     10 |    13   (0)|     10 |00:00:00.01 |      13 |
|-    4 |     STATISTICS COLLECTOR      |       |      1 |        |            |     10 |00:00:00.01 |       4 |
|     5 |      TABLE ACCESS FULL        | T2    |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       4 |
|  *  6 |     INDEX UNIQUE SCAN         | PK_T1 |     10 |      1 |     0   (0)|     10 |00:00:00.01 |       9 |
|  *  7 |    TABLE ACCESS BY INDEX ROWID| T1    |     10 |      1 |     1   (0)|     10 |00:00:00.01 |      10 |
|-    8 |   TABLE ACCESS FULL           | T1    |      0 |      1 |     1   (0)|      0 |00:00:00.01 |       0 |
----------------------------------------------------------------------------------------------------------------
Outline Data
-------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('12.1.0.1')
      DB_VERSION('12.1.0.1')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$5DA710D3")
      UNNEST(@"SEL$2")
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      FULL(@"SEL$5DA710D3" "T2"@"SEL$2")
      INDEX(@"SEL$5DA710D3" "T1"@"SEL$1" ("T1"."ID"))
      LEADING(@"SEL$5DA710D3" "T2"@"SEL$2" "T1"@"SEL$1")
      USE_NL(@"SEL$5DA710D3" "T1"@"SEL$1")
      NLJ_BATCHING(@"SEL$5DA710D3" "T1"@"SEL$1")
      END_OUTLINE_DATA
  */
Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("ID"="ID" AND "NAME"="NAME")
   6 - access("ID"="ID")
   7 - filter("NAME"="NAME")
Note
-----
   - this is an adaptive plan (rows marked '-' are inactive)
52 rows selected.

8.換成exists看看.

select id,name from t2 where exists ( select null from t1 where t1.id=t2.id and t1.name =t2.name);
select id,name from t1 where exists ( select null from t2 where t2.id=t1.id and t2.name =t1.name);

SCOTT@test01p> @dpc '' outline,adaptive
PLAN_TABLE_OUTPUT
--------------------------------------
SQL_ID  by9m9cvtgybq8, child number 0
-------------------------------------
select id,name from t1 where exists ( select null from t2 where t2.id=t1.id and t2.name =t1.name)
Plan hash value: 1238133714
-------------------------------------------------------------------------------------------------------------------------------------------
|   Id  | Operation                     | Name  | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------
|     0 | SELECT STATEMENT              |       |      1 |        |     8 (100)|     10 |00:00:00.01 |      22 |       |       |          |
|- *  1 |  HASH JOIN                    |       |      1 |     10 |     8   (0)|     10 |00:00:00.01 |      22 |  1096K|  1096K|          |
|     2 |   NESTED LOOPS                |       |      1 |        |            |     10 |00:00:00.01 |      22 |       |       |          |
|     3 |    NESTED LOOPS               |       |      1 |     10 |     8   (0)|     10 |00:00:00.01 |      12 |       |       |          |
|-    4 |     STATISTICS COLLECTOR      |       |      1 |        |            |     10 |00:00:00.01 |       3 |       |       |          |
|     5 |      SORT UNIQUE              |       |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       3 |  2048 |  2048 | 2048  (0)|
|     6 |       TABLE ACCESS FULL       | T2    |      1 |     10 |     3   (0)|     10 |00:00:00.01 |       3 |       |       |          |
|  *  7 |     INDEX UNIQUE SCAN         | PK_T1 |     10 |      1 |     0   (0)|     10 |00:00:00.01 |       9 |       |       |          |
|  *  8 |    TABLE ACCESS BY INDEX ROWID| T1    |     10 |      1 |     1   (0)|     10 |00:00:00.01 |      10 |       |       |          |
|-    9 |   TABLE ACCESS FULL           | T1    |      0 |      1 |     1   (0)|      0 |00:00:00.01 |       0 |       |       |          |
-------------------------------------------------------------------------------------------------------------------------------------------
Outline Data
-------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('12.1.0.1')
      DB_VERSION('12.1.0.1')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$5DA710D3")
      UNNEST(@"SEL$2")
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      FULL(@"SEL$5DA710D3" "T2"@"SEL$2")
      INDEX(@"SEL$5DA710D3" "T1"@"SEL$1" ("T1"."ID"))
      LEADING(@"SEL$5DA710D3" "T2"@"SEL$2" "T1"@"SEL$1")
      USE_NL(@"SEL$5DA710D3" "T1"@"SEL$1")
      NLJ_BATCHING(@"SEL$5DA710D3" "T1"@"SEL$1")
      SEMI_TO_INNER(@"SEL$5DA710D3" "T2"@"SEL$2")
      END_OUTLINE_DATA
  */
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("T2"."ID"="T1"."ID" AND "T2"."NAME"="T1"."NAME")
   7 - access("T2"."ID"="T1"."ID")
   8 - filter("T2"."NAME"="T1"."NAME")

Note
-----
   - this is an adaptive plan (rows marked '-' are inactive)

9. in ,exists後一點點小問題會漏掉id相等,name為NULL的情況,繼續測試:
insert into t2 values (11,null);
update t1 set name=null where id=11;
commt;

SCOTT@test01p> select /*+ OPT_PARAM('_convert_set_to_join' 'true') */ * from t1 intersect select * from t2;
        ID NAME
---------- --------------------
         7 testtest
         8 testtest
         2 testtest
         5 testtest
         1 testtest
         3 testtest
         6 testtest
        10 testtest
         4 testtest
         9 testtest
        11
11 rows selected.
--實際上看前面的執行計劃,就很容易理解filter(SYS_OP_MAP_NONNULL("T1"."NAME")=SYS_OP_MAP_NONNULL("T2"."NAME"))的含義.


SCOTT@test01p> select id,name from t1 where exists ( select null from t2 where t2.id=t1.id and t2.name =t1.name);
        ID NAME
---------- --------------------
         1 testtest
         2 testtest
         3 testtest
         4 testtest
         5 testtest
         6 testtest
         7 testtest
         8 testtest
         9 testtest
        10 testtest

10 rows selected.

SCOTT@test01p> select id,name from t1 where (id,name) in ( select id,name from t2);
        ID NAME
---------- --------------------
         1 testtest
         2 testtest
         3 testtest
         4 testtest
         5 testtest
         6 testtest
         7 testtest
         8 testtest
         9 testtest
        10 testtest
10 rows selected.

--如果使用in,exists,寫成這樣.
select id,name from t1 where (id,name) in ( select id,name from t2)
union all
select id,name from t1 where (id) in ( select id from t2 where t2.name is null) and  t1.name is null ;

select id,name from t2 where (id,name) in ( select id,name from t2)
union all
select id,name from t2 where (id) in ( select id from t1 where t1.name is null) and  t2.name is null ;

select id,name from t1 where exists ( select null from t2 where t2.id=t1.id and (t2.name =t1.name or (t1.name is null and t2.name is null)));

select id,name from t2 where exists ( select null from t1 where t1.id=t2.id and (t1.name =t2.name or (t2.name is null and t1.name is null)));

12.猜測函式SYS_OP_MAP_NONNULL的意義:
SCOTT@test01p> select SYS_OP_MAP_NONNULL(id) c10 ,SYS_OP_MAP_NONNULL(name) ,t2.*,dump(id,16) c20,dump(name,16) c40 from t2;
C10        SYS_OP_MAP_NONNULL_NAM         ID NAME                 C20                  C40
---------- ---------------------- ---------- -------------------- -------------------- ----------------------------------------
C10200     746573747465737400              1 testtest             Typ=2 Len=2: c1,2    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10300     746573747465737400              2 testtest             Typ=2 Len=2: c1,3    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10400     746573747465737400              3 testtest             Typ=2 Len=2: c1,4    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10500     746573747465737400              4 testtest             Typ=2 Len=2: c1,5    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10600     746573747465737400              5 testtest             Typ=2 Len=2: c1,6    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10700     746573747465737400              6 testtest             Typ=2 Len=2: c1,7    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10800     746573747465737400              7 testtest             Typ=2 Len=2: c1,8    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10900     746573747465737400              8 testtest             Typ=2 Len=2: c1,9    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10A00     746573747465737400              9 testtest             Typ=2 Len=2: c1,a    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10B00     746573747465737400             10 testtest             Typ=2 Len=2: c1,b    Typ=1 Len=8: 74,65,73,74,74,65,73,74
C10C00     FF                             11                      Typ=2 Len=2: c1,c    NULL

11 rows selected.

--從輸出結果應該猜到大概.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/267265/viewspace-1257033/,如需轉載,請註明出處,否則將追究法律責任。

相關文章