INSERT の前と後の EXISTS はどちらが速いですか?
-
21-09-2019 - |
質問
SQL Server に SP があり、毎分数百回実行され、受信トラフィックをデータベースと照合してチェックする必要があります。現時点では次のことを行っています
INSERT INTO table
SELECT @value1,@value2 WHERE NOT EXISTS
(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2);
ただし、一緒に行くこともできます
IF NOT EXISTS(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2)
INSERT INTO table (value1,value2) VALUES (@value1,@value2);
どちらが速いでしょうか?両者に大きな違いはないような気がしますが、私は昔から TSQL があまり得意ではありません...=/
アップデート:おっと...これは、EXISTS がレコードが存在するかどうかを検索するために複数の値を使用するため、一意の制約が機能しないことを意味します。それを反映するためにサンプルを編集しました...
解決
無数のこの質問に対するコメントとその答えを追加した後、私はそれに答えるに自分の行くを持っています。
私は元々の質問で提案された提案された2間のパフォーマンスに大きな違いを期待していません。一方で、レイ尖ったアウトとして、第二のアプローチは、挿入のためのいくつかの準備をしてからあなたを救うかもしれないが、一方で、RDBMSは、通常、最初のソリューションのように、バッチ文で最高の性能が得られます。
KMとDVKは、一意性のテストは、暗黙的になりますが、あなたのUNIQUE
文を周りのエラー処理のいくつかの種類を追加するために、あなたが必要になりますINSERT
制約を追加することをお勧めします。私は、これはすでに2つの列をカバーするインデックスを持っていると仮定して、追加のパフォーマンス、を追加する必要がありますなぜ苦労スポッティングを持っているの。あなたはこのようなインデックスを持っていない場合は、を、それを追加し、より高いパフォーマンスのためのあなたの必要性を再考。の
私の知る限りは問題ではないはず。何かがDBMSの胃の「内側」で行わチェックを持っていることによって得られる場合には、そのゲインがちょうど頭上上げて、重複が存在する場合にエラーを処理に関連付けられていることにより、アップ食べられるかもしれません。
<時間>一番下の行:、私のお勧めは、あなたが3つの提案ソリューションの実証テストを実行することをあなたはまだ自身がパフォーマンスのために欠除見つけた場合、インデックスがすでに適所にあると仮定しています。予想される入力データをシミュレートする小さなプログラムをでっち上げる、および重複の妥当な量を含む、数十億行を離れて3つの溶液のそれぞれを吹きます。これを行う、あなたの結果を投稿してください: - )
他のヒント
両方のバは間違っています。ま挿入ペアの重複@value1,@,値2, 保証.
く、正しく扱うことを強制独自の制約 二つの 列常に挿入し取り扱いに制約違反)になります:
ALTER TABLE Table ADD CONSTRAINT uniqueValue1Value UNIQUE (value1, values2);
とを挿入す:
BEGIN TRY
INSERT INTO Table (value1, value2) VALUES (@value1, @value2);
END TRY
BEGIN CATCH
DECLARE @error_number int, @error_message NVARCHAR(4000), @xact_state INT;
SET @error_number = ERROR_NUMBER();
SET @error_message = ERROR_MESSAGE();
SET @xact_state = XACT_STATE();
IF (@xact_state = -1)
BEGIN
ROLLBACK TRANSACTION;
END
IF (@error_number != 2627) /* 2627 is ' Cannot insert duplicate key in object ...' */
BEGIN
RAISERROR(N'Error inserting into Table: %i %s', 16,1, @errror_number, @error_message);
END
ENd CATCH
これらが複雑で、一つ一つの要因は、素晴らしいホテル名 正確性.で、これまでより簡単に比べ、ロックヒントに基づく。この最もperformant解はみました。すべての他のソリューションが必要で少なくとも二つの的に検証することを挿入することができ、挿入).
ほとんど同時の環境では、同時INSERT
はあなたの2番目のクエリでIF NOT EXISTS
とINSERT
の間で発生する可能性があります。
あなたの最初のクエリは、クエリが実行されてまで、新しいレコードを挿入することは不可能となりますので、クエリの最後まで解除されませんれます。
、それは調べたレコードに共有ロックを配置しますただし、この動作だけに頼るべきではありません。 UNIQUE
に追加value
制約を置きます。
はそれが唯一のデータベースは、より一貫性のあることはありませんが、より高速の最初の問合せを行いますインデックスを作成します。
あなたは値が一意になりたい場合は、その理由だけで値の一意性制約を作成しないで、SELECTせずにINSERTを行うと、優雅に制約違反エラーを処理?
それは速くこれらのいずれかよりも近づいたと思います。
また、あなたの最初のアプローチにはない作品 - 。あなたが選択するために、取得時点で、あなたはまだ選択した値を挿入し、明らかにあなただけの挿入見つけるでしょう。
それを実行し、エラーを無視します(値に一意の制約があると仮定します)...
BEGIN TRY
INSERT INTO Table (value) VALUES (@value);
END TRY
BEGIN CATCH
PRINT 'it was already in there!'
END CATCH
以来 これは1分間に何百回も実行されます, 、ロックヒントを SELECT とトランザクションに追加する必要があります。 競合状態を回避する
(SELECT * FROM Table WITH (UPDLOCK, HOLDLOCK) WHERE value = @value);
ただし、INSERT だけを実行し、重複する制約エラーを無視するという私が提案したアイデアは、競合状態も回避します。
、私は2番目のオプションは速いだろうと思います。存在するが失敗した場合、最初の1で、それはいくつかのテーブル名とフィールド名を検索可能性があると何が起こることはありません挿入するための準備のに対し、SQL Serverは、挿入のためのセットアップのいずれかの種類を行う必要はありません。しかし、私は、クエリアナライザでそれを試してみて、計画が言う見るであろう。