2011-03-25 65 views
1

我正在为并发用户插入我的表上发生死锁。我正在发射的sp是相对简单的插入和更新SQL 2008中的死锁

SET NOCOUNT ON; 

begin try 
    begin tran 

    DECLARE @idoc INT 
    declare @ProcessedResponse table (
     candidateInstanceID int, 
     assessmetID   int, 
     sectionID   int, 
     itemID    int, 
     clientID    int, 
     displayTypeID  int, 
     respondedAt   datetime, 
     responseTime   float, 
     marksObtained  float, 
     processedresponseXML xml, 
     resultDescription varchar(255), 
     reportedIssue  bit) 

    -- insert into @PartialResponse 
    EXEC sp_xml_preparedocument 
     @idoc OUTPUT, 
     @Processed_Responses 

    insert into @ProcessedResponse 
    SELECT * 
    FROM OPENXML(@idoc, '/Processed_Responses/Processed_Response', 1) 
       WITH (Candidate_Instance_ID int, 
        Assessment_ID   int, 
        Section_ID   int, 
        Item_ID    int, 
        Client_ID    int, 
        Display_Type_ID  int, 
        Responded_At   datetime, 
        Response_Time   float, 
        Marks_Obtained  float, 
        Processed_XML   text, 
        Result_Description text, 
        Reported_Issue  bit) 

    INSERT INTO Processed_Response 
       (Candidate_Instance_ID, 
       Assessment_ID, 
       Section_ID, 
       Client_ID, 
       Item_ID, 
       Display_Type_ID, 
       Responded_At, 
       Response_Time, 
       Marks_Obtained, 
       Processed_XML, 
       Result_Description, 
       Reported_Issue) 
    SELECT pr.candidateInstanceID, 
      pr.assessmetID, 
      pr.sectionID, 
      pr.clientID, 
      pr.itemID, 
      pr.displayTypeID, 
      cast(pr.respondedAt as datetime), 
      pr.responseTime, 
      case pr.marksObtained 
      when 0 then null 
      else pr.marksObtained 
      end, 
      CAST(pr.processedresponseXML AS XML), 
      pr.resultDescription, 
      pr.reportedIssue 
    FROM @ProcessedResponse pr 

    update pr 
    set pr.Client_ID = a.Assessment_Owner 
    from Processed_Response pr 
      join Assessment a 
      on pr.Assessment_ID = a.Assessment_Id 
    where pr.Candidate_Instance_ID = @Candidate_Instance_ID 

    update Candidate_Instance 
    set Instance_Status = 'Completed', 
      Instance_End_Time = GETDATE() 
    where Candidate_Instance_Id = @Candidate_Instance_ID 

    commit tran 
end try 

begin catch 
    DECLARE @ErrorMessage NVARCHAR(4000); 
    DECLARE @ErrorSeverity INT; 
    DECLARE @ErrorState INT; 

    SELECT @ErrorMessage = ERROR_MESSAGE(), 
      @ErrorSeverity = ERROR_SEVERITY(), 
      @ErrorState = ERROR_STATE(); 

    rollback tran 

    -- Use RAISERROR inside the CATCH block to return error 
    -- information about the original error that caused 
    -- execution to jump to the CATCH block. 
    RAISERROR (@ErrorMessage,-- Message text. 
       @ErrorSeverity,-- Severity. 
       @ErrorState -- State. 
    ); 
end catch 

任何人都可以帮助我,谢谢。

+0

'Processed_Response'与'Candidate_Instance'有外键关系吗?这些表上有哪些索引?如果'Processed_Response.Client_ID'上没有索引,则应该添加一个。 – 2011-03-25 14:08:07

+0

这真的是代码吗?因为在你显示的代码中,'@ Candidate_Instance_ID'永远不会被初始化。 – 2011-03-25 15:54:42

+0

@Damien OP提到这是一个sp - 我认为这是一个参数 – 2011-03-25 16:12:45

回答

0

它需要两位代码才能死锁,所以这个代码是否自己死锁?不知道表结构和索引用法很难诊断。是你的更新 - 选择(update pr...)表扫描并锁定整个表?等

毫无疑问,我会把BEGIN TRANS移动到INSERT INTO Processed_Response之前,你不需要把所有的局部变量的东西放在事务中。尽可能缩短交易时间。

设置了SQL Server Profiler并获得了一个死锁图形跟踪,你会看到两个相互碰撞的SQL,并从那里开始。