天天看點

[20160314]關于sql寫法問題使用=還是用in

[20160314]關于sql寫法問題使用=還是用in.txt

--昨天看http://www.dbaxiaoyu.com/archives/2618,我第一次看到的感覺應該可以轉化為連接配接查詢,順便做一個例子重複測試:

1.環境:

SCOTT@test01p> @ ver1

PORT_STRING                    VERSION        BANNER                                                                               CON_ID

------------------------------ -------------- -------------------------------------------------------------------------------- ----------

IBMPC/WIN_NT64-9.1.0           12.1.0.1.0     Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production              0

SCOTT@book> create table t as select * from dba_objects ;

Table created.

SCOTT@book> create unique index pk_t on t(object_id);

Index created.

-- create index i_t_DATA_OBJECT_ID on t(DATA_OBJECT_ID);

--分析Method_Opt => 'FOR ALL COLUMNS SIZE 1 '。

2.測試:

SCOTT@book> alter session set statistics_level=all ;

Session altered.

SCOTT@test01p> select * from t where data_object_id = ( select data_object_id from t where object_id=40);

OWNER  OBJECT_NAME          SUBOBJECT_  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE             CREATED             LAST_DDL_TIME       TIMESTAMP           STATUS  T G S  NAMESPACE EDITION_NA SHARING       E O

------ -------------------- ---------- ---------- -------------- ----------------------- ------------------- ------------------- ------------------- ------- - - - ---------- ---------- ------------- - -

SYS    I_OBJ5                                  40             40 INDEX                   2013-06-28 09:03:29 2013-06-28 09:03:29 2013-06-28:09:03:29 VALID   N N N          4            NONE            Y

Plan hash value: 159606559

----------------------------------------------------------------------------------------------------------------------------------------

| Id  | Operation                    | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |

|   0 | SELECT STATEMENT             |      |      1 |        |       |   431 (100)|          |      1 |00:00:00.18 |    1546 |   1539 |

|*  1 |  TABLE ACCESS FULL           | T    |      1 |     11 |  1265 |   429   (1)| 00:00:01 |      1 |00:00:00.18 |    1546 |   1539 |

|   2 |   TABLE ACCESS BY INDEX ROWID| T    |      1 |      1 |     7 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       3 |      0 |

|*  3 |    INDEX UNIQUE SCAN         | PK_T |      1 |      1 |       |     1   (0)| 00:00:01 |      1 |00:00:00.01 |       2 |      0 |

Query Block Name / Object Alias (identified by operation id):

-------------------------------------------------------------

   1 - SEL$1 / T@SEL$1

   2 - SEL$2 / T@SEL$2

   3 - SEL$2 / T@SEL$2

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter("DATA_OBJECT_ID"=)

   3 - access("OBJECT_ID"=40)

--如果仔細看執行計劃,可以發現并不存在連接配接,執行計劃先選擇3->2->1.如果換成in:

SCOTT@test01p> select * from t where data_object_id in ( select data_object_id from t where object_id=40);

Plan hash value: 2201121422

|   1 |  NESTED LOOPS                |      |      1 |      1 |   122 |   431   (1)| 00:00:01 |      1 |00:00:00.18 |    1546 |   1539 |

|*  2 |   TABLE ACCESS BY INDEX ROWID| T    |      1 |      1 |     7 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       3 |      0 |

|*  4 |   TABLE ACCESS FULL          | T    |      1 |      1 |   115 |   429   (1)| 00:00:01 |      1 |00:00:00.18 |    1543 |   1539 |

   1 - SEL$5DA710D3

   2 - SEL$5DA710D3 / T@SEL$2

   3 - SEL$5DA710D3 / T@SEL$2

   4 - SEL$5DA710D3 / T@SEL$1

   2 - filter("DATA_OBJECT_ID" IS NOT NULL)

   4 - filter(("DATA_OBJECT_ID" IS NOT NULL AND "DATA_OBJECT_ID"="DATA_OBJECT_ID"))

--使用nested loop連接配接,作者認為不會出現連接配接查詢,如果看outline部分,可以發現使用in查詢時提示使用unnest,感覺作者使用錯提示.

--改寫如下:

select * from t where data_object_id = ( select /*+ unnest */ data_object_id from t where object_id=40);

|   0 | SELECT STATEMENT             |      |      1 |        |       |   431 (100)|          |      1 |00:00:00.20 |    1546 |   1539 |

|   1 |  NESTED LOOPS                |      |      1 |      1 |   122 |   431   (1)| 00:00:01 |      1 |00:00:00.20 |    1546 |   1539 |

|*  4 |   TABLE ACCESS FULL          | T    |      1 |      1 |   115 |   429   (1)| 00:00:01 |      1 |00:00:00.20 |    1543 |   1539 |

--很明顯使用unnest提示後,執行計劃也可以改寫成連接配接查詢.甚至能交換次序.

select /*+ leading(t) */ * from t where data_object_id = ( select /*+ unnest */ data_object_id from t where object_id=40);

--執行計劃如下:

Plan hash value: 268617269

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

| Id  | Operation                    | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |

|   0 | SELECT STATEMENT             |      |      1 |        |       |   431 (100)|          |      1 |00:00:00.18 |    1545 |   1539 |       |       |          |

|*  1 |  HASH JOIN                   |      |      1 |      1 |   122 |   431   (1)| 00:00:01 |      1 |00:00:00.18 |    1545 |   1539 |  1978K|  1092K| 2425K (0)|

|*  2 |   TABLE ACCESS FULL          | T    |      1 |   8182 |   918K|   429   (1)| 00:00:01 |   8182 |00:00:00.15 |    1542 |   1539 |       |       |          |

|*  3 |   TABLE ACCESS BY INDEX ROWID| T    |      1 |      1 |     7 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       3 |      0 |       |       |          |

|*  4 |    INDEX UNIQUE SCAN         | PK_T |      1 |      1 |       |     1   (0)| 00:00:01 |      1 |00:00:00.01 |       2 |      0 |       |       |          |

3.使用= 最大的問題是僅僅傳回單行才行,多行才會報錯.

--改成非唯一索引看看.

drop index pk_t;

create  index pk_t on t(object_id);

--檢視執行計劃:

Plan hash value: 145684969

------------------------------------------------------------------------------------------------------------------------------------------------

| Id  | Operation                            | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |

|   0 | SELECT STATEMENT                     |      |      1 |        |       |   431 (100)|          |      1 |00:00:00.19 |    1546 |   1540 |

|*  1 |  TABLE ACCESS FULL                   | T    |      1 |     11 |  1265 |   429   (1)| 00:00:01 |      1 |00:00:00.19 |    1546 |   1540 |

|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| T    |      1 |      1 |     7 |     2   (0)| 00:00:01 |      1 |00:00:00.02 |       3 |      1 |

|*  3 |    INDEX RANGE SCAN                  | PK_T |      1 |      1 |       |     1   (0)| 00:00:01 |      1 |00:00:00.02 |       2 |      1 |

--可以看出這個問題關鍵在于查詢内層走的索引必須唯一,傳回單行,這樣的查詢才可以轉換為連接配接查詢.如果不确定傳回的行數,執行計劃

--不會采用連接配接查詢.

4.在使用10053看看:

create unique index pk_t on t(object_id);

SCOTT@test01p> @ 10053on 12

SCOTT@test01p> Select * from t where data_object_id = ( select /*+ unnest */ data_object_id from t where object_id=40);

SCOTT@test01p> @ 10053off

Final query after transformations:******* UNPARSED QUERY IS *******

ELECT /*+ UNNEST */ "T"."OWNER" "OWNER","T"."OBJECT_NAME" "OBJECT_NAME","T"."SUBOBJECT_NAME"

"SUBOBJECT_NAME","T"."OBJECT_ID" "OBJECT_ID","T"."DATA_OBJECT_ID" "DATA_OBJECT_ID","T"."OBJECT_TYPE"

"OBJECT_TYPE","T"."CREATED" "CREATED","T"."LAST_DDL_TIME" "LAST_DDL_TIME","T"."TIMESTAMP" "TIMESTAMP","T"."STATUS"

"STATUS","T"."TEMPORARY" "TEMPORARY","T"."GENERATED" "GENERATED","T"."SECONDARY" "SECONDARY","T"."NAMESPACE"

"NAMESPACE","T"."EDITION_NAME" "EDITION_NAME","T"."SHARING" "SHARING","T"."EDITIONABLE"

"EDITIONABLE","T"."ORACLE_MAINTAINED" "ORACLE_MAINTAINED"

 FROM "SCOTT"."T" "T","SCOTT"."T" "T"

WHERE "T"."DATA_OBJECT_ID" = "T"."DATA_OBJECT_ID"

  AND "T"."OBJECT_ID"      = 40

kkoqbc: optimizing query block SEL$841DDE77 (#1)

--可以發現最終查詢轉化為以上查詢.