2016-12-07 58 views
8

我遇到了一些我不能解釋的奇怪現象。執行計劃與預期不符

我使用下面的查詢:

MERGE INTO Main_Table t 
USING Stg_Table s 
ON(s.site_id = t.site_id) 
WHEN MATCHED THEN 
    UPDATE SET t.arpu_prev_period = s.arpu_prev_period 
       .... --50 more columns 
    where t.period_code = 201612 

Stg_Table:索引(SITE_ID)

MAIN_TABLE:
- 索引(Period_code,SITE_ID)
- 注 - 通過period_code
分區 - 我嘗試在Site_Id上單獨添加索引,執行計劃相同。

我期待一個使用單分區掃描的執行計劃,但我得到Partition list all

這是執行計劃:

6 | 0 | MERGE STATEMENT  |        | 
7 | 1 | MERGE    | Main_Table     | 
8 | 2 | VIEW    |        | 
9 | 3 | HASH JOIN   |        | 
10 | 4 |  TABLE ACCESS FULL | Stg_Table      | 
11 | 5 |  PARTITION LIST ALL|        | 
12 | 6 |  TABLE ACCESS FULL| Main_Table     | 

編輯:對於澄清,如果它是不明確的,我不是在尋找如何使甲骨文的答案,只掃描單個分區,我已經知道把t.period_code = 201612放在ON條款中會沒問題。我的問題是 - 爲什麼oracle不會評估應該只過濾特定分區的WHERE子句?

+2

如果您將't.period_code = 201612'移動到'ON'狀態而不是'WHERE',您是否得到相同的計劃? – Kacper

+0

Oracle版本? –

+0

11g @DuduMarkovitz – sagi

回答

3

好像沒有對UPDATE的WHERE子句進行優化。

create table t (n,x) as select level n,-1 x from dual connect by level <= 1000000; 
create table s (n,x) as select level n,-1 x from dual connect by level <= 1000000; 

merge into t 
using s 
on (s.n = t.n) 
when matched then update set t.x = s.x where 1=2 
; 

enter image description here

+0

感謝您的回答。如果您能找到關於此行爲的文檔,我很樂意批准此文件。 – sagi

+0

沒什麼我熟悉的。這是不太可能找到他們**不做的優化Oracle的文檔,但我認爲演示很好。相比之下,看看'select * from t where 1 = 2'的執行計劃。 –

1

請考慮將t.period_code = 201612移交給我們:on (t.period_code = 201612 and s.site_id = t.site_id)。我認爲你的查詢是試圖訪問所有分區PARTITION LIST ALL,這就是問題所在。

如果添加訪問單個分區的條件應該會更好。

另一種選擇是:

MERGE INTO (select * from Main_Table where period_code = 201612) t 
USING Stg_Table s 
ON(t.period_code = 201612 and s.site_id = t.site_id) 
WHEN MATCHED THEN 
    UPDATE SET t.arpu_prev_period = s.arpu_prev_period 
       .... --50 more columns 
    where t.period_code = 201612 

直接指向該更新只適用於一個分區。

編輯

好了,所以試圖回答的問題是爲什麼。 Oracle無法將兩個條件合併爲一個。 where包含有關分區的信息,但對於需要先應用ON條件的已加入數據應用where。但在那個時候,它沒有關於分區的信息,只是site_id,所以它決定掃描所有分區。您需要在第一步(即加入on)通知Oracle您要使用的分區。

換句話說申請where其中包含有關分區的信息首先需要解決:

MERGE INTO Main_Table t 
USING Stg_Table s 
ON(s.site_id = t.site_id) 

,並在這裏你必須訪問所有分區。 wherewhen matched的一部分,所以首先我們需要確定是否有任何匹配或沒有關於分區的知識。

+0

感謝您的回答,是的,它確實只訪問了一個分區。請參閱編輯我的問題,我想我誤導了你.. – sagi

+0

@sagi好的我已經添加了一些解釋,爲什麼我認爲它會這樣。 – Kacper

+0

解釋完全錯誤。這不是優化器的工作方式。 –

1

應區分合並插入/更新條款的WHERE clause和SELECT語句的WHERE clause之間進行。

合併條款是一般saing - 不更新不要插入。一般情況下的一代ACCESS謂詞不是微不足道的。

正如其他人在最簡單的情況下指出的那樣,只有一個UPDATE WHERE子句,沒有執行從11g開始的ACCESS謂詞。

它也documentes這樣

merge_update_clause

,如果你想在數據庫中執行僅當指定條件爲真更新操作指定where_clause。該條件可以引用數據源或目標表。如果條件不成立,則數據庫在將行合併到表中時跳過更新操作。

即謂詞skipps更新不是行源中的記錄。

+0

我沒有與Oracle公司任命。文件引用不應該在SO上受到懲罰! –