2017-05-22 3 views
1

Ich rufe eine gespeicherte Prozedur auf, die entweder INSERT oder UPDATE ausführt, abhängig davon, ob der Prozedurschlüssel in einer Tabelle vorhanden ist.Wie Deadlock in gespeicherter SQL Server-Prozedur zu verhindern?

Bisher funktionierte das Verfahren wie erwartet. Bis unsere Benutzerbasis anfing, in der Größe zu wachsen. Heute habe ich den folgenden Fehler, die durch einen Neustart des Application Pool läuft der Dienst aufgelöst wurde:

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.

Wie können Sie Deadlock in einer SQL Server gespeicherte Prozedur verhindern?

Ich überprüfte die this link, was darauf hindeutet, dass es möglicherweise ein Problem mit einem SELECT AND UPDATE gleichzeitig ausgeführt haben, die den Deadlock verursacht. Aber meine Prozedur trennt die Anweisungen mit einer IF..ELSE Bedingung, so dass beide nicht gleichzeitig ausgeführt werden konnten.

Stored Procedure:

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 

Antwort

1

Würde der Tabellen- und Index DDL und voller Deadlock Graph sehen müssen sicher sein, aber wahrscheinlich müssen nur die Zielzeile auf dem anfänglichen Lese sperren.

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

Sie könnten der Sam Saffron upsert approach wie so verwenden:

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 
Verwandte Themen