2015-04-12 300 views
3

我有一個簡單的查詢正在運行。有一個日期條件,我一旦刪除,查詢就返回結果。它的格式爲'31 -MAR-15'的日期字段。我不明白爲什麼這種情況會使查詢速度變慢。提前致謝。Oracle - 查詢運行速度很慢

SELECT 
    substr(a.id, 1, 2) AS country, 
    count(DISTINCT a.id) AS id_count, 
    sum(a.amount)  AS amount 
FROM table1 a 
    JOIN table2 b ON a.id = b.id 
    JOIN table3 c ON b.party_id = c.party_id 
WHERE a.prod_type = 'INS' 
    AND c.acct_type = 'LON' 
    AND substr(a.id, 1, 2) = 'US' 
    AND a.dump_dt = '31-MAR-15' 
    AND substr(id, 4, 8) = '20150303' 
GROUP BY substr(a.id, 1, 2); 

解釋計劃:

PLAN_TABLE_OUTPUT 
Plan hash value: 255044277 

------------------------------------------------------------------------------------------------------------ 
| Id | Operation       | Name     | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT     |      |  1 | 121 | 125K (1)| 00:25:08 | 
| 1 | HASH GROUP BY     |      |  1 | 121 | 125K (1)| 00:25:08 | 
| 2 | VIEW       | VW_DAG_0    |  1 | 121 | 125K (1)| 00:25:08 | 
| 3 | HASH GROUP BY     |      |  1 | 98 | 125K (1)| 00:25:08 | 
| 4 |  NESTED LOOPS     |      |  |  |   |   | 
| 5 |  NESTED LOOPS     |      |  1 | 98 | 125K (1)| 00:25:08 | 
| 6 |  MERGE JOIN CARTESIAN  |      | 12613 | 800K| 21133 (2)| 00:04:14 | 
|* 7 |  TABLE ACCESS BY INDEX ROWID| TABLE1     |  1 | 45 | 46 (0)| 00:00:01 | 
|* 8 |   INDEX RANGE SCAN   | DATA_DATE__STG_BACKUP2 | 1040 |  |  6 (0)| 00:00:01 | 
| 9 |  BUFFER SORT    |      | 182K| 3564K| 21087 (2)| 00:04:14 | 
|* 10 |   TABLE ACCESS FULL   | TABLE3     | 182K| 3564K| 21087 (2)| 00:04:14 | 
|* 11 |  INDEX RANGE SCAN   | BSB_PARTYID_IDX  | 22 |  |  3 (0)| 00:00:01 | 
|* 12 |  TABLE ACCESS BY INDEX ROWID | TABLE2     |  1 | 33 | 10 (0)| 00:00:01 | 
------------------------------------------------------------------------------------------------------------ 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    7-filter(SUBSTR(A.ID, 4, 8) = '20150303' AND SUBSTR(A.ID, 1, 2) = 'US' 
       AND A.PROD_TYPE = 'INS') 
    8 - access(A.DUMP_DT = '31-MAR-15') 
    10 - filter(C.ACCT_TYPE = 'LON') 
    11 – access(B.PARTY_ID = C.PARTY_ID) 
    12 - filter(A.ID = B.ID) 
+1

什麼'dump_dt'的類型?你有什麼指數?什麼是解釋計劃? – Mat

+0

您是否檢查過DUMP_DT上有索引? – PhillipD

+2

這對Oracle來說是無效的SQL,它不支持用於別名表的'AS'關鍵字。有些東西你沒有告訴我們......正如其他人所說的DDL表和解釋計劃是_essential_爲了讓你得到一個很好的答案,它看起來好像你將日期存儲爲字符串,這總是一個配方災難和最後'SUBSTR(ID,4,9)'返回9個字符,而不是8,所以除非ID少於13個字符長度,我期望'SUBSTR(ID,4,9)='20150303'始終返回什麼也沒有,這意味着你的查詢不會返回任何東西你能否澄清你的問題? – Ben

回答

1

貌似優化器是顯著低估的行數上TABLE1應用這些4個謂詞後返回。

A.PROD_TYPE = 'INS' 
SUBSTR(A.ID, 1, 2) = 'US' 
A.DUMP_DT = '31-MAR-15' 
SUBSTR(ID, 4, 8) = '20150303' 

(略題外話:它的安全使用ANSI文字date '2015-03-31'而不是隱式轉換字符串'31-MAR-15'和聲明有一些錯誤,好像缺少了前2個謂語之間的狀態和失蹤的。 A.在過去的謂語前)

首先,確保有對所有表準確的統計數據,看看是否改變了解釋計劃:

begin 
    dbms_stats.gather_table_stats(user, 'TABLE1'); 
    dbms_stats.gather_table_stats(user, 'TABLE2'); 
    dbms_stats.gather_table_stats(user, 'TABLE3'); 
end; 
/

的「SMA rt列「,ID,使得很難估計應用條件後返回的行數。如果是來不及更改數據模型,你至少可以爲Oracle提供了一些擴展統計信息,以幫助其應對謂詞:

select dbms_stats.create_extended_stats(user, 'TABLE1', '(SUBSTR(ID, 1, 2))') from dual; 
select dbms_stats.create_extended_stats(user, 'TABLE1', '(SUBSTR(ID, 4, 8))') from dual; 

我猜測SUBSTR(A.ID, 1, 2) = 'US'是一種流行的價值,但沒有擴展統計信息Oracle不會知道這一點。額外的直方圖可能會顯着增加基數。然後優化器不會選擇兩個不相關表之間的笛卡爾連接。

-1

嘗試使用Oracle提示來選擇穩定計劃或您可以使用招:

.... 
And A.DUMP_DT+0 = to_date('31-MAR-15','dd-mon- rr') 
... 
1

我在WHERE子句超過A.ID

A.ID LIKE 'US_20150303%' 

簡化條件與

substr(a.id, 1, 2) = 'US' AND substr(id, 4, 8) = '20150303' 

相同的效果,並且在情況下列A.ID被索引,應用SUBSTR(a.ID,..)函數的事實使索引無用。

在另一方面,a.dump_dt似乎是一個DATE類型列,所以在此列應用過濾器的優選方式可能是

a.dump_dt = TO_DATE('31-MAR-15', 'DD-MON-RR') 

,而不是

a.dump_dt = '31-MAR-15' 

後者主要依賴於運行查詢的Oracle客戶端的NLS_DATE_FORMAT,並且在某些情況下,可能會通過忽略對索引的使用而對性能產生負面影響,該索引的使用範圍爲a.dump_dt

因此改寫查詢看起來是這樣的:

SELECT 
    SUBSTR(A.ID, 1, 2) AS country, 
    COUNT(DISTINCT A.ID) AS id_count, 
    SUM(A.amount)  AS amount 
FROM table1 A 
    JOIN table2 b ON A.ID = b.ID 
    JOIN table3 c ON b.party_id = c.party_id 
WHERE A.prod_type = 'INS' 
    AND c.acct_type = 'LON' 
    AND A.ID LIKE 'US_20150303%' 
    AND A.dump_dt = TO_DATE('31-MAR-15', 'DD-MON-RR') 
GROUP BY SUBSTR(A.ID, 1, 2); 
+0

您好,請問您可以編輯您的答案以解釋此查詢的作用以及它如何修復所問的問題?只有代碼答案是不鼓勵的,並且可能會被刪除。謝謝。 –

相關問題