8

SQL Serverに1分間に数百回実行される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はレコードが存在するかどうかを見つけるために複数の値を使用するため、一意の制約は機能しません。それを反映するようにサンプルを編集しました...

4

6 に答える 6

5

どちらのバリアントも正しくありません。重複する @value1、@value2、保証のペアを挿入します。

これを処理する正しい方法は、2 つの列に一意の制約を適用し、常に INSERT して制約違反を処理することです。

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

これらは複雑に見えるかもしれませんが、正しさという名前の小さな詳細を考慮に入れる必要があります。これは、ロック ヒント ベースのソリューションと比較すると、はるかに簡単です。これは、最もパフォーマンスの高いソリューションでもあります。シークは 1 回だけです。他のすべてのソリューションでは、少なくとも 2 つのシークが必要です (1 つは挿入できることを検証するため、もう 1 つは挿入するため)。

于 2010-02-17T19:03:19.813 に答える
1

値を一意にしたい場合は、値に一意の制約を作成し、SELECT なしで INSERT を実行して、制約違反エラーを適切に処理してみませんか?

それは、これらのアプローチのいずれよりも高速です。

また、最初のアプローチは機能しません。選択するまでに、すでに値が挿入されているため、select は挿入したばかりのものを明らかに見つけます。

于 2010-02-17T16:44:19.493 に答える
1

ただそれを行い、エラーを無視します(値に一意の制約があると仮定します)...

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 だけで重複制約エラーを無視するという私の提案したアイデアは、競合状態も回避します。

于 2010-02-17T16:47:18.320 に答える
0

推測する必要がある場合は、2 番目のオプションの方が速いと思います。SQL Server は、exist が失敗した場合に挿入のために何らかのセットアップを行う必要はありませんが、最初のサーバーでは、いくつかのテーブルとフィールド名を検索し、決して起こらない挿入の準備をする可能性があります。ただし、クエリ アナライザーで試して、プランの内容を確認します。

于 2010-02-17T16:45:38.930 に答える