多くの人がMERGE
の使用を提案します 、しかし私はそれに対してあなたに警告します。デフォルトでは、複数のステートメントを超えて並行性や競合状態からユーザーを保護することはありませんが、他の危険をもたらします:
- SQLServerのMERGEステートメントには注意が必要です
- MERGEを使用する場合の回避策
- SQLServerUPSERTパターンとアンチパターン
この「より単純な」構文が利用可能であっても、私はこのアプローチを好みます(簡潔にするためにエラー処理は省略されています):
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE dbo.table SET ... WHERE PK = @PK;
IF @@ROWCOUNT = 0
BEGIN
INSERT dbo.table(PK, ...) SELECT @PK, ...;
END
COMMIT TRANSACTION;
このUPSERT
の詳細 ここでのアプローチ:
- このUPSERTアンチパターンの使用を中止してください
多くの人がこの方法を提案します:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
UPDATE ...
END
ELSE
BEGIN
INSERT ...
END
COMMIT TRANSACTION;
ただし、これにより、更新する行を見つけるためにテーブルを2回読み取る必要がある場合があります。最初のサンプルでは、行を1回だけ見つける必要があります。 (どちらの場合も、最初の読み取りから行が見つからない場合は、挿入が発生します。)
他の人はこの方法を提案します:
BEGIN TRY
INSERT ...
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 2627
UPDATE ...
END CATCH
ただし、ほとんどすべての挿入が失敗するまれなシナリオを除いて、最初に防止できたはずの例外をSQL Serverにキャッチさせる以外の理由がない場合、これははるかにコストがかかる場合に問題があります。私はここで同じことを証明します:
- TRY/CATCHに入る前に潜在的な制約違反をチェックする
- さまざまなエラー処理手法によるパフォーマンスへの影響
1つのステートメントで何が得られると思うかわかりません。私はあなたが何も得ないと思います。 MERGE
は単一のステートメントですが、それでも実際には複数の操作を実行する必要があります-そうではないと思わせる場合でも。