2016-07-21 6 views
1

私は、行キーがまだ存在しない場合は、行をテーブルに挿入するストアドプロシージャを持っています。select-insertプロシージャでロック・ヒントが必要ですか?

create proc EmployeeInsertIfNotExists 
    (@id int, @name varchar(50)) 
as 
begin 
    SET XACT_ABORT ON 

    begin transaction 

    if not exists(select * from tbl where id = @id) 
     insert into tbl(id, name) 
     values(id, name) 

    commit transaction 
end 

このストアドプロシージャは、実際には2つのステートメントで、選択と挿入が可能です。私はトランザクションの内部で両方のステートメントを実行し、その間に何も起こらずに例外が発生するようにします。 id列は主キーですので、同じIDを2回挿入しないようにしたいと思います。

私の質問は次のとおりです。問題を防ぐために十分な予防措置ですか? select文にヒントを入れる必要はありますか?その場合はHOLDLOCK, TABLOCKXが必要ですか?これは私にとって新しい材料です。

EDIT:あなたはserializableへのトランザクション分離レベルをマークしたい

create proc EmployeeInsertIfNotExists 
    (@id int, @name varchar(50)) 
as 
begin 
    SET XACT_ABORT ON 
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 

    begin transaction 

    if not exists(select * from tbl where id = @id) 
     insert into tbl(id, name) 
     values(id, name) 

    commit transaction 
end 

答えて

1

推奨答え。それ以外の場合は、トランザクションの途中で同じIDの行を挿入できます。これは「ファントム行」として知られています。

テーブル全体をロックする必要はありません。正しい分離レベルを使用することで、SQL Serverはロックを適用する方法をよりスマートにすることができます。

+0

私は貼り付けた2番目のものに手順を変更する必要がありますか? merge'文を使ってトランザクションを完全に回避することはできますか? – user2023861

+0

はい、2番目のバージョンが動作します。いいえ、マージはアトミックではありません。元のバージョンと同じ問題があります。 –

+1

これは、あなたがやろうとしていることのための方法です。 Serializableはあなたのマシンのパフォーマンスを傷つける(kill?)。 idにユニークな制約がある場合、他の誰もその列に複数のキー値を挿入できないことが保証されます。 procからの戻り値は、挿入が失敗したことを示し、別のキー値で再試行できます。 –

関連する問題