SO を閲覧しているときに、まだ存在しないレコードを挿入するための「最良の」アプローチについて、次の質問/ディスカッションを見つけました。私を驚かせた声明の 1 つは、[Remus Rusanu] の次のような発言でした。
どちらのバリアントも正しくありません。重複する @value1、@value2、保証のペアを挿入します。
チェックがINSERTから「分離」されている構文については同意しますが(明示的なロック/トランザクション管理は存在しません)。このような他の提案された構文にこれが当てはまる理由と時期を理解するのに苦労しています
INSERT INTO mytable (x)
SELECT @x WHERE NOT EXISTS (SELECT * FROM mytable WHERE x = @x);
私は(別の)何が最善/最速の議論を始めたくありませんし、構文が一意のインデックス/制約(またはPK)を「置き換える」ことができるとは思いませんが、この構造がどのような状況でダブルスを引き起こす可能性があるかを本当に知る必要があります.過去にこの構文を使用しており、今後も使用し続けるのは安全ではないのではないかと考えています。
私が思うに、INSERT と SELECT は両方とも同じ (暗黙の) トランザクション内にあるということです。クエリは、関連するレコード (キー) に IX ロックを取得し、クエリ全体が終了するまで解放しないため、レコードが挿入された後にのみ解放されます。このロックは、挿入が完了するまで他のすべての接続がロックを取得できないため、他のすべての接続が同じ INSERT を作成するのをブロックします。そうして初めて、彼らはロックを取得し、レコードが既に存在するかどうかを自分で確認し始めます。
私見では、調べる最善の方法はテストすることなので、ラップトップで次のコードをしばらく実行しています。
テーブルを作成
CREATE TABLE t_test (x int NOT NULL PRIMARY KEY (x))
以下は、非常に多くの接続を並行して実行します)
SET NOCOUNT ON
WHILE 1 = 1
BEGIN
INSERT t_test (x)
SELECT x = DatePart(ms, CURRENT_TIMESTAMP)
WHERE NOT EXISTS ( SELECT *
FROM t_test old
WHERE old.x = DatePart(ms, CURRENT_TIMESTAMP) )
END
これまでのところ、注意すべき点は次のとおりです。
- エラーは発生していません (まだ)
- CPU がかなり熱くなっています =)
- テーブルはすぐに 300 レコードを保持しました (datetime の 3 ミリ秒の「精度」のため)。
アップデート:
上記の私の例は、私が意図したことをしていないことがわかりました。複数の接続が同じレコードを同時に挿入しようとする代わりに、最初の 1 秒後に既存のレコードを挿入しないようにしました。次の接続でクエリをコピーして貼り付けて実行するのにおそらく約1秒かかったため、重複の危険はありませんでした。一日中、ロバの耳をかぶっています...
とにかく、私は目前の問題に沿ったものになるようにテストを調整しました(同じ表を使用)
SET NOCOUNT ON
DECLARE @midnight datetime
SELECT @midnight = Convert(datetime, Convert(varchar, CURRENT_TIMESTAMP, 106), 106)
WHILE 1 = 1
BEGIN
INSERT t_test (x)
SELECT x = DateDiff(ms, @midnight, CURRENT_TIMESTAMP)
WHERE NOT EXISTS ( SELECT *
FROM t_test old
WHERE old.x = DateDiff(ms, @midnight, CURRENT_TIMESTAMP))
END
そして、見よ、出力ウィンドウには、次の行に沿って多くのエラーが表示されるようになりました
メッセージ 2627、レベル 14、状態 1、行 8 PRIMARY KEY 制約 'PK__t_test__3BD019E521C3B7EE' の違反。>重複したキーをオブジェクト 'dbo.t_test' に挿入できません。重複キーの値は (57581873) です。
参考: Andomar が指摘したように、HOLDLOCK および/または SERIALIZABLE ヒントを追加すると、問題は実際に「解決」されますが、その後、多くのデッドロックが発生することが判明しました。
やるべきコードレビューがかなりあると思います...