如何在存储过程中多次更新 table 时避免死锁?

How to avoid deadlock while updating a table multiple times in a stored procedure?

我有一个存储过程,我在其中多次更新 table,但是在我的情况下,当多个会话 运行 这个过程时,这会导致死锁。

我曾尝试使用 Begin Trans 和 Commit 语句,但对我不起作用。我读过创建索引可以解决我的问题,但它有什么帮助以及我应该在哪个列上创建(哪种类型的)索引?

UPDATE lessonPlanSkill SET 
  PreviousProficiency = lessonPlanSkill.CurrentProficiency ,
  PreviousAccuracy = lessonPlanSkill.CurrentAccuracy  ,
  CoveragePercentage = Calculations.CoveragePercentage,
  AccuracyPercentage = Calculations.AccuracyPercentage,
  CurrentAccuracy = Calculations.AccuracyPercentage,
  TotalQuestions = Calculations.AttemptedQuestions,
  CorrectQuestions = Calculations.CorrectAttempts,
  CurrentAchievementScore = Calculations.CurrentAchievedScore,
  TotalAchievementScore = Calculations.TotalAchievementScore,
  TimeSpentInMin=TimeSpentInMin+@ModuleAttemptHistoryTimeSpent,
  AchievementPercentage = CASE WHEN (Calculations.TotalAchievementScore>0) 
  THEN (Calculations.CurrentAchievedScore/Calculations.TotalAchievementScore)*100 
  END
FROM #tblLearnerProficiency Calculations 
INNER JOIN dbo.UserLessonPlanSkill lessonPlanSkill ON lessonPlanSkill.UserId = @pUserId AND lessonPlanSkill.LessonPlanSharedTrackingId = @LessonPlanSharedTrackingId AND lessonPlanSkill.SkillId = Calculations.SkillId AND lessonPlanSkill.IsDeleted = 0

-- Insert statement to insert some data in UserLessonPlanSkill table
-- Again update statement which is most likely causing deadlock with above update statement
UPDATE lessonPlanSkill SET 
  CurrentProficiency = ISNULL(logic.ProficiencyLevel,1),
  ModifiedOn = GETUTCDATE(),
  IsSkillStuck = CASE WHEN (logic.ProficiencyLevel = @PROFICIENT_STATUS) THEN 0 ELSE IsSkillStuck END  
FROM #tblLearnerProficiency Calculations 
INNER JOIN dbo.UserLessonPlanSkill lessonPlanSkill ON 
lessonPlanSkill.UserId = @pUserId AND 
lessonPlanSkill.LessonPlanSharedTrackingId = @LessonPlanSharedTrackingId 
AND lessonPlanSkill.SkillId = Calculations.SkillId AND 
lessonPlanSkill.IsDeleted = 0
INNER JOIN dbo.JudgementLogic logic WITH(NOLOCK) ON logic.FormulaId = 
Calculations.FormulaId AND logic.IsDeleted = 0
WHERE 
Calculations.AccuracyPercentage BETWEEN AccuracyMinPercentage AND 
AccuracyMaxPercentage  AND
Calculations.CoveragePercentage BETWEEN CoverageMinPercentage AND 
CoverageMaxPercentage 

-- After some queries, another update statement comes at the end of this stored procedure updating same table.

UPDATE CurrentResult SET 
  MedianPercentage = ((CoveragePercentage/MaxQuestionCount)*AccuracyPercentage)
FROM dbo.UserLessonPlanSkill CurrentResult  
INNER JOIN #tblFilteredSkills skills ON skills.SkillId = 
CurrentResult.SkillId 
AND CurrentResult.LessonPlanSharedTrackingId = @LessonPlanSharedTrackingId
AND CurrentResult.UserId = @pUserId 
AND CurrentResult.IsDeleted = 0

PS:这是从 profiler

中提取的 deadlock graph and here is description

我已通过创建临时 table、插入所需数据并更新该临时 table 或将新数据插入该临时 table 来解决此问题。最终 insert/update 实际 table 与基于主键(索引)的 temp table 中的值。这解决了我的僵局问题。 PS:如果有人得到更好的答案,请发表评论或添加新答案!!