行がない場合のみ挿入する
質問
私はいつも以下のようなものを使って実現していました。
INSERT INTO TheTable
SELECT
@primaryKey,
@value1,
@value2
WHERE
NOT EXISTS
(SELECT
NULL
FROM
TheTable
WHERE
PrimaryKey = @primaryKey)
...しかし、一度負荷がかかると、主キー違反が発生しました。 これは、このテーブルにまったく挿入しない唯一のステートメントです。 ということは、上記のステートメントはアトミックではないということでしょうか?
問題は、これを自由に再現することはほとんど不可能だということです。
おそらく、次のようなものに変えることができると思います。
INSERT INTO TheTable
WITH
(HOLDLOCK,
UPDLOCK,
ROWLOCK)
SELECT
@primaryKey,
@value1,
@value2
WHERE
NOT EXISTS
(SELECT
NULL
FROM
TheTable
WITH
(HOLDLOCK,
UPDLOCK,
ROWLOCK)
WHERE
PrimaryKey = @primaryKey)
とはいえ、ロックの使い方が間違っているのか、ロックの使いすぎなのか、何なんでしょうね。
私は、stackoverflow.com で、回答が "IF (SELECT COUNT(*) ... INSERT" などを提案している他の質問を見ましたが、私はいつも、単一の SQL 文がアトミックであるという(おそらく間違った)前提で考えていました。
誰か考えをお持ちですか?
どのように解決するのですか?
についてはどうですか? "JFDI"。 のパターンはどうでしょうか?
BEGIN TRY
INSERT etc
END TRY
BEGIN CATCH
IF ERROR_NUMBER() <> 2627
RAISERROR etc
END CATCH
真面目な話、これはロック無しで最も速く、特に大容量では最も同時性が高いです。 UPDLOCKがエスカレートして、テーブル全体がロックされたらどうするんですか?
レッスン4を読む :
<ブロッククオート
レッスン4
インデックスのチューニングに先立ち、upsert procを開発する際、まず信頼できるのは
If Exists(Select…)
行がどのアイテムに対しても実行され、重複を禁止してくれると信じていました。しかし、そうではありませんでした。同じアイテムが同じミリ秒にアップサートにヒットし、両方のトランザクションが存在しないことを確認して挿入を実行したため、短期間で何千もの重複が発生しました。多くのテストの後、解決策は、ユニーク インデックスを使用し、エラーをキャッチし、トランザクションが行を見ることができるように再試行して、挿入の代わりに更新を実行することでした。
関連
-
[解決済み] LINQでInclude()は何をするのですか?
-
[解決済み] SQLのカラム名があいまいな場合のクエリエラー
-
[解決済み] JOINとINNER JOINの違いについて
-
[解決済み] SQL Serverでテーブルからカラム名を取得するにはどうすればよいですか?
-
[解決済み] T-SQLでnot equalには!=と<>のどちらを使うべきですか?
-
[解決済み] ある列の最大値を持つ行を取得する
-
[解決済み] SQLite - UPSERT *not* INSERT or REPLACE
-
[解決済み] NOT IN vs NOT EXISTS
-
[解決済み] SQL/mysql - Select distinct/UNIQUE but return all column?
-
[解決済み] SQL Server の Insert Update ストアド プロシージャ
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
plsql-stored-procedure ORA-06550 エラー処理
-
[解決済み] アドホッククエリとは何ですか?
-
[解決済み] SQL Server の DateTime データ型から日付だけを返す方法
-
[解決済み] MongoDBに "like "を使ってクエリを実行する方法
-
[解決済み] INNER JOINよりもCROSS APPLYを使用すべきなのはどのような場合ですか?
-
[解決済み] MySQLでFULL OUTER JOINを行うにはどうすればよいですか?
-
[解決済み] SQL ServerにおけるINSERT OR UPDATEに関する解決策
-
[解決済み] 項目xにアクセスできるように文字列を分割するにはどうすればよいですか?
-
[解決済み] SQL ServerでGROUP BYを使って文字列を連結する方法とは?
-
[解決済み】SQL Server 存在しない場合に挿入する。