2017-05-22 5 views
1

テーブルにあるプロシージャキーに依存するINSERTまたはUPDATEのいずれかを実行するストアドプロシージャを呼び出しています。どのようにSQL Serverストアドプロシージャのデッドロックを防ぐには?

これまでのところ、手順は期待通りに機能していました。ユーザーベースの規模が拡大し始めるまで。今日、私はサービスを実行しているアプリケーションプールを再起動することで解決した、次のエラーを得た:

InsertDDM_UserDashboard error: RequestError: Transaction (Process ID 64) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

どのようにSQL Serverのストアドプロシージャでのデッドロックを防ぐことができますか?

私はSELECTと同時にデッドロックの原因となっている問題が発生している可能性があることを示唆しているthis linkを確認しました。しかし、私の手続きでは、IF..ELSEという条件でステートメントを分けるので、両方を同時に実行することはできませんでした。

ストアドプロシージャ:

SET ANSI_NULLS ON 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [dbo].[InsertDDM_UserDashboard] 
    @p_email VARCHAR(255), 
    @p_dashboardPreferences VARCHAR(4000), 
    @p_userDefaultDashboard VARCHAR(500) 
AS 

IF (NOT EXISTS(SELECT * FROM [dbo].[DDM_UserProfile] WHERE Email = @p_email)) 
BEGIN  

    INSERT INTO [dbo].[DDM_UserProfile] 
      ([Email] 
      ,[DashboardPreferences] 
      ,DefaultDashboard 
      ) 
    VALUES 
      (@p_email 
      ,@p_dashboardPreferences 
      ,@p_userDefaultDashboard 
      ) 

END ELSE BEGIN 

     UPDATE [dbo].[DDM_UserProfile] 
     SET [DashboardPreferences][email protected]_dashboardPreferences 
     WHERE [Email][email protected]_email 

     UPDATE [dbo].[DDM_UserProfile] 
     SET [email protected]_userDefaultDashboard 
     WHERE [Email][email protected]_email 

END 

答えて

1

は確かにテーブルとインデックスDDLと完全なデッドロックのグラフを参照する必要がありますが、あなたはおそらく、最初の読み取りにターゲット行をロックする必要があります。 EG

ALTER PROCEDURE [dbo].[InsertDDM_UserDashboard] 
    @p_email VARCHAR(255), 
    @p_dashboardPreferences VARCHAR(4000), 
    @p_userDefaultDashboard VARCHAR(500) 


AS 
begin 
begin transaction 

IF (NOT EXISTS(SELECT * FROM [dbo].[DDM_UserProfile] with (updlock, holdlock) WHERE Email = @p_email)) 
BEGIN  
INSERT INTO [dbo].[DDM_UserProfile] 
     ([Email] 
     ,[DashboardPreferences] 
     ,DefaultDashboard 
     ) 
    VALUES 
     (@p_email 
     ,@p_dashboardPreferences 
     ,@p_userDefaultDashboard 
     ) 

END 

ELSE 
BEGIN 
    UPDATE [dbo].[DDM_UserProfile] 
    SET [DashboardPreferences][email protected]_dashboardPreferences, 
     [email protected]_userDefaultDashboard 
    WHERE [Email][email protected]_email 

END 

commit transaction 
end 
1

あなたがそうのようなSam Saffron upsert approachを使用することができます。

create procedure dbo.ddm_UserProfile_Dashboard_upsert (
    @p_email varchar(255) 
    , @p_dashboardPreferences varchar(4000) 
    , @p_userDefaultDashboard varchar(500) 
) as 
begin 
    set nocount, xact_abort on; 
    begin tran; 
    update up 
     set [email protected]_dashboardPreferences 
     , DefaultDashboard [email protected]_userDefaultDashboard 
     from dbo.ddm_UserProfile up with (serializable) 
     where up.Email = @p_email; 
    if @@rowcount = 0 
    begin; 
     insert into dbo.ddm_UserProfile (Email, DashboardPreferences, DefaultDashboard) 
     values (@p_email, @p_dashboardPreferences, @p_userDefaultDashboard); 
    end; 
    commit tran; 
end; 
go 
関連する問題