2013-03-13 13 views
5

私は値に私の一時テーブルを選択し、そのようなデータベースに挿入するストアドプロシージャを実行しているを選択1分に何千もの要求を処理するサーバーでは時間がかかる)、EmailAddress列のインデックスに一意制約エラー「UNIQUE KEY制約の違反」が発生します。INSERT INTO .. ..ユニーク制約違反

私は重複値を渡していないことを確認できます。私がいたとしても、DISTINCTに捕らえられるべきです。

-SQL Server 2008の -Stored PROC + SELECTとINSERTその後の間、INSERTを完了し、同じ/異なるストアドプロシージャに別の呼び出しがあったことが起こるんでし+ JDBCのCallableStatementの

をトランザクションを使用していません似たようなデータですか?もしそうなら、それを防ぐ最善の方法は何でしょうか?

いくつかのアイデア:本番環境でこの1つのSQL Serverと一度に通信する「クライアント」のインスタンスが多数存在するため、最初の反応は並行性の問題でしたが、自分では複製できないようです。それは私が持っていた最高の推測ですが、それは今のところどこにも行きません。これは、運用環境と比較して負荷が重要でないステージング環境では発生しません。それが私が並行性の問題を探し始めた主な理由でした。

+1

両方のEmailAddressのNULL値が一意のキー制約に違反する可能性があります。この列がヌル可能な場合は、挿入を '存在しない 'として書き換えるかもしれません。 –

+0

良い点。私はコード内のnullsに対してチェックを行いますが、私は再びSQLでそれをチェックできると思います。 –

答えて

5

エラーはおそらく、同時に2つのセッションが挿入を実行しているために発生しています。

MERGEを使用すると、SQLコードをより安全にすることができます。 Aaron Bertrandのコメントによると(ありがとう!)、you have to include a with (holdlock) hint to make merge really safe

; merge emails e with (holdlock) 
using #EmailInfoTemp eit 
on  e.EmailAddress = eit.EmailAddress 
when not matched then insert 
     (EmailAddress) values (eit.EmailAddress) 

mergeの文は、チェックし、「挿入」、「一致しない」だの間には、他のセッションがこっそりすることはできないことを保証するために適切なロックがかかります。

mergeを使用できない場合は、クライアント側の問題を解決できます。同時に2つのインサートが実行されていないことを確認してください。これは通常、mutexまたは他の同期構造では簡単です。

+1

'' MELGE'は 'HOLDLOCK'ヒントを追加しない限り、必ずしも安全ではありません(http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx )。 –

+0

@AaronBertrand:ありがとう。 MERGEのMSDNページに「READPASTを指定していないときに[ターゲットで]指定するとINSERT操作がUNIQUE制約に違反する可能性があります」というメッセージが表示されます。だから、あなたが 'readpast'を指定しない限り安全だと思いました。 – Andomar

+1

はいマイクロソフトでは、通常、破損する可能性のあるすべてのケースを文書化することはありません。このドキュメントでは、[まだ解決されていないこれらのバグ(下にスクロールするもの)]については触れていません。](http://www.sqlperformance.com/2013/02/t-sql-queries/another-マージバグ)。 :-) –

関連する問題