2016-12-07 4 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     | 

EDIT:それは明確ではなかった場合、私は単一パーティションのみをスキャンするには、Oracleを作成する方法についての答えを明確にするため見ていませんよ、私はすでにt.period_code = 201612ON句に入れることはうまくいくことを知っています。私の質問は - oracleが特定のパーティションだけをフィルタリングするWHERE句を評価しないのはなぜですか?

+2

't.period_code = 201612'を' WHERE'ではなく 'ON'条件にすると同じ計画が得られますか? – 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

私はよく知っていることはありません。 **私が行っていない最適化に関するオラクルのドキュメントを見つけることはまずありませんが、デモではうまくいきます。これと比較して、 '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 

直接その更新が唯一のパーティションにあるのポイントに。

EDIT

[OK]を、なぜ質問に答えるためにしようとしています。 Oracleは2つの条件を1つに結合することはできません。 whereにはパーティションに関する情報が含まれていますが、whereを結合データに適用するには、まずON条件を適用する必要があります。しかし、その時点ではパーティションに関する情報が全くありません。ただsite_idなので、すべてのパーティションでスキャンを行うことにしました。どのパーティションを使用するかは、最初のステップ(onに参加)でOracleに通知する必要があります。あなたはすべてのパーティションにアクセスする必要が

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

、ここで:それは解決する必要がある最初のパーティションに関する情報が含まれているwhereを適用するつまり

wherewhen matchedの一部ですので、最初に、パーティションに関する知識がなくても一致するかどうかを判断する必要があります。

+0

答えをいただきありがとうございます。はい、実際には1つのパーティションにしかアクセスしませんでした。私の質問の編集を参照してください、私はあなたを欺いたと思う.. – sagi

+0

@サギOKなぜそれがそうなると思ういくつかの説明を追加しました。 – Kacper

+0

説明は間違っています。これはオプティマイザが動作する方法ではありません。 –

1

区別がマージ挿入/更新句とSELECT文のWHERE clauseWHERE clause間でなされるべきです。

MERGE句は、一般的saingである - を更新しないを挿入しないでください。一般的なケースでACCESS述語の生成は自明ではありません。

最も単純なケースでは、UPDATE WHERE句が1つのみであると指摘されているように、11グラムで実行されるACCESS述語の生成はありません。

また、このような

merge_update_clause

としてdocumentesされ、データベースが指定した条件が真である場合にのみ、更新操作を実行する場合where_clauseが指定します。条件は、データ・ソースまたはターゲット表のいずれかを参照できます。条件が真でない場合、データベースは行を表にマージするときに更新操作をスキップします。

つまり、述語skippsは行ソースのレコードではありません。

+0

私はOracle社に任命されていません。書類からの引用は、罰せられるべきではありません! –

関連する問題