C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: SQLServerのMERGE文のパフォーマンスについて


(過去ログ 177 を表示中)

[トピック内 13 記事 (1 - 13 表示)]  << 0 >>

■101484 / inTopicNo.1)  SQLServerのMERGE文のパフォーマンスについて
  
□投稿者/ ぼぼ (12回)-(2023/03/03(Fri) 18:15:59)

分類:[データベース全般] 

SQL実行の負荷観点についての質問ですが。

SQLServerでは2008Versionより、MERGE文が提供され、いわゆるUPSERTが1文で実装できるようになりましたが、
SQL実行のパフォーマンス観点では、
@存在チェックSQL発行
AInsert(or UPDATE)SQL発行
と、服問い合わせSQLと同様に2個SQLが発行されている様に見えました。

パフォーマンスの比較ではこのMERGE文を使用するより、DELETE→INSERTでの一括挿入の方がDB負荷が軽いと思っているのですが、いかがでしょうか?
お分かりになる方いらっしゃいましたら宜しくお願い致します。

参考:
https://johobase.com/sqlserver-merge-insert-update-delete/
https://learn.microsoft.com/ja-jp/sql/t-sql/statements/merge-transact-sql?view=sql-server-ver15
引用返信 編集キー/
■101486 / inTopicNo.2)  Re[1]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ 伝説のカレー (80回)-(2023/03/04(Sat) 14:35:04)
No101484 (ぼぼ さん) に返信

ケースバイケースだと思います
レコードの数やインデックスの数やwhereの条件やコミット間隔などでいくらでも変動しそうな気がします
実際のデータでベンチマークテストやったが良いです
引用返信 編集キー/
■101487 / inTopicNo.3)  Re[2]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ ぼぼ (13回)-(2023/03/04(Sat) 16:37:17)
No101486 (伝説のカレー さん) に返信

ありがとうございます。確かに実際作ってみれば分かりますね。
ただ、物理的にSQLの発行回数で考えると11回に対し21回ですよね。。
確かにテーブルに何万件入ってるのかでまた変わって来そうですけど、それでも(INDEX効かしても)前者かなと思います。。

中間テーブルに10件更新
◆DELETE→INSERT
@DELETE
A10件INSERT

◆MERGE
@全件UPDATE(削除フラグOFFとか)
A10件MERGE(実質x2)


引用返信 編集キー/
■101488 / inTopicNo.4)  Re[3]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ ぼぼ (15回)-(2023/03/04(Sat) 19:55:57)
No101487 (ぼぼ さん) に返信
すみません。Merge文ってそもそも2つのテーブルを比較して入れるんですね。
Mergeの言葉通りですが、Upsertと勘違いしてました。
結局、存在チェックのSQLはかけないといけないんですね。
引用返信 編集キー/
■101490 / inTopicNo.5)  Re[4]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ KOZ (391回)-(2023/03/05(Sun) 14:37:41)
2023/03/05(Sun) 14:38:19 編集(投稿者)

No101487 (ぼぼ さん) に返信
> 中間テーブルに10件更新
> ◆DELETE→INSERT
> @DELETE
> A10件INSERT
>
> ◆MERGE
> @全件UPDATE(削除フラグOFFとか)
> A10件MERGE(実質x2)

比較するとしたら、

◆DELETE→INSERT
@ 10件分のキーを指定して DELETE
A 10件INSERT

◆MERGE
@ 10件MERGE

では?

No101488 (ぼぼ さん) に返信
> すみません。Merge文ってそもそも2つのテーブルを比較して入れるんですね。

CREATE TABLE HOGE(ITEM1 VARCHAR(2), ITEM2 VARCHAR(2))
というテーブルがあったとして

MERGE HOGE AS A
USING (SELECT 1 AS DUMMY) AS B ON A.ITEM1 = 'A'
WHEN MATCHED
THEN UPDATE SET ITEM2 = 'C'
WHEN NOT MATCHED BY TARGET
THEN INSERT (ITEM1, ITEM2) VALUES ('A', 'B')

のように書けます。

引用返信 編集キー/
■101492 / inTopicNo.6)  Re[1]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ 大谷刑部 (226回)-(2023/03/06(Mon) 10:08:38)
No101484 (ぼぼ さん) に返信
> パフォーマンスの比較ではこのMERGE文を使用するより、DELETE→INSERTでの一括挿入の方がDB負荷が軽いと思っているのですが、いかがでしょうか?
> お分かりになる方いらっしゃいましたら宜しくお願い致します。

レコード数やWhere句の複雑度にもよりますが、一般論としてはその通りと思います。
ただ、MERGEを採用するかどうかは性能観点よりSQLを発行するプログラム側でのIF分岐が必要なくなるため、単純にステップ数が減らせる→可読性が上がることの効果の方が大きいような気もします。

また、ログを詳細に取っていて、「登録」なのか「更新」なのかを区別して件数を書きだす必要がある開発現場では不向きですね。
あくまでMERGEを発行したことでの影響レコード数しかたしか取得できないので。
引用返信 編集キー/
■101493 / inTopicNo.7)  Re[2]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ 大谷刑部 (227回)-(2023/03/06(Mon) 10:16:35)
No101492 (大谷刑部 さん) に返信
> ■No101484 (ぼぼ さん) に返信
>>パフォーマンスの比較ではこのMERGE文を使用するより、DELETE→INSERTでの一括挿入の方がDB負荷が軽いと思っているのですが、いかがでしょうか?
>>お分かりになる方いらっしゃいましたら宜しくお願い致します。
>
> レコード数やWhere句の複雑度にもよりますが、一般論としてはその通りと思います。
> ただ、MERGEを採用するかどうかは性能観点よりSQLを発行するプログラム側でのIF分岐が必要なくなるため、単純にステップ数が減らせる→可読性が上がることの効果の方が大きいような気もします。
>
> また、ログを詳細に取っていて、「登録」なのか「更新」なのかを区別して件数を書きだす必要がある開発現場では不向きですね。
> あくまでMERGEを発行したことでの影響レコード数しかたしか取得できないので。

すいません逆の認識だったのですね。
MERGEの方が本数が少ない分、トータルコストは多分低いです。
ただ、性能上、どっちが処理時間を要するかはケースバイケースでしょう。
DeleteもWhere句が複雑だとものすごく時間がかかるケースもあるのでInsertがUpdateよりかからないから、本数と逆転してDelete-Insertの方がかえって速くなるとも必ずしも言えないかと。
引用返信 編集キー/
■101495 / inTopicNo.8)  Re[3]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ ぼぼ (16回)-(2023/03/06(Mon) 21:56:00)
No101490 (大谷刑部 さん) に返信
>比較するとしたら、
>◆MERGE
>@ 10件MERGE
>では?

ありがとうございます。
実際、実装のイメージで言うと
初回001,002,003と入っており、2回目では002,003,004とパラメータ受けした場合、
001が残ってしまうはずなので、DELETE→INSERT時と同様に一旦初期化する必要があると思います。
→論理削除の場合。
引用返信 編集キー/
■101496 / inTopicNo.9)  Re[4]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ ぼぼ (17回)-(2023/03/06(Mon) 21:58:59)
No101492 (大谷刑部 さん) に返信
>MERGEを採用するかどうかは性能観点よりSQLを発行するプログラム側でのIF分岐が必要なくなるため、単純にステップ数が減らせる→可読性が上がることの効果の方が大きいような気もします。

なるほどです。そういう見方も確かにありますね。
引用返信 編集キー/
■101497 / inTopicNo.10)  Re[4]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ KOZ (392回)-(2023/03/06(Mon) 22:10:32)
2023/03/07(Tue) 07:57:18 編集(投稿者)

No101495 (ぼぼ さん) に返信
> 初回001,002,003と入っており、2回目では002,003,004とパラメータ受けした場合、
> 001が残ってしまうはずなので、DELETE→INSERT時と同様に一旦初期化する必要があると思います。
> →論理削除の場合。

違う更新を比較しても意味がありません。
全件 DELETE して INSERT という処理では MERGE の出番は無いように思います。
(更新データ用のテーブルを作れば WHEN NOT MATCHED BY SOURCE を使って書けないこともないですが)
引用返信 編集キー/
■101505 / inTopicNo.11)  Re[4]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ 大谷刑部 (228回)-(2023/03/07(Tue) 13:16:03)
No101495 (ぼぼ さん) に返信
> ■No101490 (大谷刑部 さん) に返信
> >比較するとしたら、
> >◆MERGE
> >@ 10件MERGE
> >では?
>
> ありがとうございます。
> 実際、実装のイメージで言うと
> 初回001,002,003と入っており、2回目では002,003,004とパラメータ受けした場合、
> 001が残ってしまうはずなので、DELETE→INSERT時と同様に一旦初期化する必要があると思います。
> →論理削除の場合。

そのケースで001を消さなきゃいけない仕様なんだとすると、Delete-Insert一択ですよね。多分。
MergeはあくまであればUpdateなければInsertを一つのSQLで記載できる構文なので、001を消しつつMergeを使いたいなら、2回目のレコードが存在しない(not Exist等)を条件にDeleteして
Merge発行となるのでそもそもSQL文の本数を減らせる効果が半減するので採用するメリットが低くなると思います。

引用返信 編集キー/
■101516 / inTopicNo.12)  Re[4]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ 魔界の仮面弁士 (3582回)-(2023/03/08(Wed) 10:06:07)
No101484 (ぼぼ さん) に返信
> @存在チェックSQL発行
> AInsert(or UPDATE)SQL発行
> と、服問い合わせSQLと同様に2個SQLが発行されている様に見えました。
2 個発行されているように見えた、というのは、
実行計画などから判断されたということでしょうか?

仮にその方法だと、既存データの更新であろうと、新規データの追加であろうと、
常に 2 回の操作が必要になってしまうかと思います。DELETE → INSERT 法も同様ですよね。

さらに DELETE → INSERT 法に至っては、データ構成次第では
断片化をより招きやすくなる可能性もありそうです。
(といっても、DELETE 後のエクステントに収まるサイズの INSERT なら HWM は変わらないですが)


たとえば 1 件だけの更新の場合は、「存在チェック SQL」は発行せずに、
 (1) UPDATE を行ってみる
 (2) その更新件数が 0 件だったら INSERT を行う
という手法もあります。

この場合、既存レコードなら(2)の操作が不要になるので、DML 操作が 1 回だけで済みます。
新規レコードの場合は(1)と(2)の両方が必要になりますけれどね。

更新件数の取得は、Transact SQL ならば @@ROWCOUNT で得られます。
あるいは ADO.NET の DbCommand.ExecuteNonQuery の戻り値や、
ADO の Command.Execute の RecordsAffected パラメーターでも得られます。


とはいえ、一度に複数レコードを同時に INSERT/UPDATE するようなケースでは使えないので
その場合は MERGE を使った方が良いでしょう。母数が多い場合、Lookup アクセスされると
探索コストが高くなってしまうので、抽出条件は主キーのみで行えるようにするか、あるいは
インデックス以外の値も条件に必要なら、付加列インデックスを用いた設計にするといった対処をとります。


No101495 (ぼぼ さん) に返信
> 実際、実装のイメージで言うと
> 初回001,002,003と入っており、2回目では002,003,004とパラメータ受けした場合、
> 001が残ってしまうはずなので、DELETE→INSERT時と同様に一旦初期化する必要があると思います。
> →論理削除の場合。

論理削除の場合と物理削除の場合とで選択肢も変わってくるわけですが、
データベース製品やそのバージョンによっては、DELETE も同時に行えることがありますね。

SQL Server で、INSERT/UPDATE/DELETE を同時に行う MERGE 構文の例
https://johobase.com/sqlserver-merge-insert-update-delete/#DELETE

Oracle で、INSERT/UPDATE/DELETE を同時に行う MERGE 構文の例
https://www.ne.jp/asahi/hishidama/home/tech/oracle/merge.html
引用返信 編集キー/
■101517 / inTopicNo.13)  Re[3]: SQLServerのMERGE文のパフォーマンスについて
□投稿者/ radian (113回)-(2023/03/08(Wed) 10:55:11)
2023/03/08(Wed) 10:59:05 編集(投稿者)

操作するデータ件数が少ない場合は、DB操作自体に掛かる時間より通信時間の方がよほど長くなるので、
DBへSQLを投げる回数が減る方が有利な場合があります。
机上の空論より、伝説のカレーさんが言うようにベンチマークを取るべきです。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -