我有一個sql查詢,當連接兩個表時速度很慢,但當我第一次查詢一個表並且查詢另一個表時,速度很快。加入Oracle時查詢速度慢,分裂成兩個查詢時速度快
環境/先決條件
Oracle版本:
Oracle數據庫11g企業版發佈11.2.0.3.0 - 64位生產
對象涉及:
cfc_materialized(物化視圖,21.5神達行)
contact(table,12,6 Mio rows)
涉及的指標:
CREATE INDEX CONTACT_CLIENT ON CONTACT(客戶);
CREATE INDEX CFC_MATERIALIZED_A_S_T ON CFC_MATERIALIZED(ASSOCIATION_TYPE,SOURCEID,TARGETID);
我已經重新計算2代表與級聯的統計=>真:
BEGIN
SYS.DBMS_STATS.GATHER_TABLE_STATS (
OwnName => '...'
,TabName => '...'
,Estimate_Percent => 0
,Degree => 4
,Cascade => TRUE
,No_Invalidate => FALSE);
END;
/
問題
我有以下查詢:
SELECT c.*
FROM contact c
WHERE c.client in (
SELECT cfc.targetid
FROM cfc_materialized cfc
WHERE cfc.sourceid = 'e95027f0-a83e-11e3-a0ae-005056aebabc'
AND cfc.association_type = 'ContactDataSharing'
)
AND c.deleted = 0;
解釋計劃:
--------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11M| 2214M| 38976 (1)| 00:07:48 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10001 | | | | | Q1,01 | P->S | QC (RAND) |
| 3 | NESTED LOOPS | | | | | | Q1,01 | PCWP | |
| 4 | NESTED LOOPS | | 11M| 2214M| 38976 (1)| 00:07:48 | Q1,01 | PCWP | |
| 5 | SORT UNIQUE | | 2164 | 196K| 10672 (1)| 00:02:09 | Q1,01 | PCWP | |
| 6 | PX RECEIVE | | 2164 | 196K| 10672 (1)| 00:02:09 | Q1,01 | PCWP | |
| 7 | PX SEND HASH | :TQ10000 | 2164 | 196K| 10672 (1)| 00:02:09 | Q1,00 | P->P | HASH |
| 8 | PX BLOCK ITERATOR | | 2164 | 196K| 10672 (1)| 00:02:09 | Q1,00 | PCWC | |
|* 9 | MAT_VIEW ACCESS FULL | CFC_MATERIALIZED | 2164 | 196K| 10672 (1)| 00:02:09 | Q1,00 | PCWP | |
|* 10 | INDEX RANGE SCAN | CONTACT_CLIENT | 5500 | | 37 (0)| 00:00:01 | Q1,01 | PCWP | |
|* 11 | TABLE ACCESS BY INDEX ROWID| CONTACT | 5474 | 550K| 973 (0)| 00:00:12 | Q1,01 | PCWP | |
--------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
9 - filter("CFC"."SOURCEID"='e95027f0-a83e-11e3-a0ae-005056aebabc' AND "CFC"."ASSOCIATION_TYPE"='ContactDataSharing')
10 - access("C"."CLIENT"="CFC"."TARGETID")
11 - filter("C"."DELETED"=0)enter code here
這需要很長時間,我想知道爲什麼在cfc_materialized上有完整的訪問權限。 將查詢拆分爲2個查詢時,速度要快得多。 第一次查詢:
SELECT cfc.targetid
FROM cfc_materialized cfc
WHERE cfc.sourceid = 'e95027f0-a83e-11e3-a0ae-005056aebabc'
AND cfc.association_type = 'ContactDataSharing';
該查詢返回2個targetids。 解釋計劃:
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2164 | 196K| 36 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| CFC_MATERIALIZED_A_S_T | 2164 | 196K| 36 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("CFC"."ASSOCIATION_TYPE"='ContactDataSharing' AND
"CFC"."SOURCEID"='e95027f0-a83e-11e3-a0ae-005056aebabc')
這裏是第二個查詢。我用的第一個查詢的輸出作爲輸入的IN參數:
SELECT *
FROM contact c
WHERE c.client in (
'e95027f0-a83e-11e3-a0ae-005056aebabc',
'eb37d3b0-a83e-11e3-a0ae-005056aebabc'
)
AND c.deleted = 0;
解釋計劃:
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2814 | 283K| 505 (0)| 00:00:07 |
| 1 | INLIST ITERATOR | | | | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| CONTACT | 2814 | 283K| 505 (0)| 00:00:07 |
|* 3 | INDEX RANGE SCAN | CONTACT_CLIENT | 2827 | | 23 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("C"."DELETED"=0)
3 - access("C"."CLIENT"='e95027f0-a83e-11e3-a0ae-005056aebabc' OR
"C"."CLIENT"='eb37d3b0-a83e-11e3-a0ae-005056aebabc')
問題
所以我的問題是,爲什麼是CBO不以類似的方式執行查詢,例如手動執行2個查詢中的查詢。我也試圖與提示查詢在2個查詢使用相同的指標,如:
SELECT /*+ index(c CONTACT_CLIENT) */ c.*
FROM contact c
WHERE c.client in (
SELECT /*+ index(cfc CFC_MATERIALIZED_A_S_T) */ cfc.targetid
FROM cfc_materialized cfc
WHERE cfc.sourceid = 'e95027f0-a83e-11e3-a0ae-005056aebabc'
AND cfc.association_type = 'ContactDataSharing'
)
AND c.deleted = 0;
但後來我得到一個更糟糕的解釋計劃:
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11M| 2214M| 305K (1)| 01:01:09 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 11M| 2214M| 305K (1)| 01:01:09 |
| 3 | SORT UNIQUE | | 2164 | 196K| 36 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | CFC_MATERIALIZED_A_S_T | 2164 | 196K| 36 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | CONTACT_CLIENT | 5500 | | 37 (0)| 00:00:01 |
|* 6 | TABLE ACCESS BY INDEX ROWID| CONTACT | 5474 | 550K| 973 (0)| 00:00:12 |
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("CFC"."ASSOCIATION_TYPE"='ContactDataSharing' AND
"CFC"."SOURCEID"='e95027f0-a83e-11e3-a0ae-005056aebabc')
5 - access("C"."CLIENT"="CFC"."TARGETID")
6 - filter("C"."DELETED"=0)
我也試圖做一個連接,而不是IN子句的像亞歷山大和StanislavL建議:
SELECT c.*
FROM contact c
JOIN cfc_materialized cfc ON c.client = cfc.targetid
WHERE cfc.sourceid = 'e95027f0-a83e-11e3-a0ae-005056aebabc'
AND cfc.association_type = 'ContactDataSharing'
AND c.deleted = 0;
,並得到了以下解釋計劃,這又是很慢(比兩個單獨的查詢速度較慢):
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11M| 2214M| 51745 (1)| 00:10:21 |
|* 1 | HASH JOIN | | 11M| 2214M| 51745 (1)| 00:10:21 |
|* 2 | INDEX RANGE SCAN | CFC_MATERIALIZED_A_S_T | 2164 | 196K| 36 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| CONTACT | 12M| 1237M| 51649 (1)| 00:10:20 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("C"."CLIENT"="CFC"."TARGETID")
2 - access("CFC"."ASSOCIATION_TYPE"='ContactDataSharing' AND
"CFC"."SOURCEID"='e95027f0-a83e-11e3-a0ae-005056aebabc')
3 - filter("C"."DELETED"=0)
另外,我相信,在這裏需要'cfc_materialized.targetid'上的索引 – Alexander