2017年1月28日土曜日

SQLServer 2008 から Merge が使える

久しぶりに本題のSQLServer です。

今まで知りませんでした。
MERGE文が使えるんですね。

SQL と言えば、言わずもがな「Select」「Insert」「Update」「Delete」の4文が基本です。
例えば、Table_A と、ほぼ同じ構造を持った Table_B があって、
必ずTable_Aが最新になっているとします。

最新になっているというのは、

1、レコードが増えている。
2、レコードが減っている。
3、レコードが更新されている。

とうことが考えられます。

この状態をTable_Bに反映させる。
例えば、夜間バッチでTable_Bを最新状態にする必要がある場合が想定されます。

今までなら、
Table_Bに不足しているレコードを特定して、Insert文を発行。
Table_Aには無いレコードを特定して、Delete文を発行。
Table_AにもTable_Bにもあるが、更新されているレコードに対して、Update文を発行。
と3回の比較処理を走らせる必要があるので、
大量のレコードの場合に、莫大なコストが必要になることがありました。

これを1回の比較で処理してしまうのが、Merge です。
まあ、言葉の意味のままのステートメントです。

私の場合、ORACLEにあるテーブルをそのままSQLServerに毎日夜間バッチでコピーしたいのですが、総レコード数は40万件以上あるのに、更新または追加されるのは、わずか1000件程度。
その1000件を最新に保つために、 Truncate で全消し、Insert で全書きをしていましたが、あまりにも非効率なのと、ディスクにも負担をかけると思います。

そこで考えたのが、リンクサーバーでORACLEに接続して、OpenQuery を発行します。
その際、更新年月日を参照して、前回処理日以降だけに絞る Where句を付けておきます。
OpenQuery なので、条件が入っても、ORACLE側で高速に処理されて返ってきます。
これで1000件程度のレコードが返ってくる。

これを一旦 Select Into ##tempTable で仮テーブルに保管して、SQLServer 側の本来保管したいテーブルと比較して、 MERGE 処理を行うことにしました。

毎日数分かかっていた処理が、数秒で完了するようになりました。

MERGE の構文自体は、他の方がたくさん例を挙げていただいているので、私は省略です。

でも、1行で書けるといっても、結構手間の必要な構文になります。

比較は1回ですが、マッチした場合の動作(通常は UpDate になるかな。)と、アンマッチの場合の動作を(私の場合は、Insert ですが、 場合によっては、 Delete になる。)それぞれ書かないとダメです。
まあ、当たり前と言えば当たり前ですけどね。

特に、 UpDate の場合は、カラムを全部書かないと(しかも、元と先の両方を書かないと)ダメなので、カラム数の多いテーブルだと、長ーい構文になっちゃいます。







0 件のコメント:

コメントを投稿