如何在存储过程中多次更新 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:如果有人得到更好的答案,请发表评论或添加新答案!!
我有一个存储过程,我在其中多次更新 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:如果有人得到更好的答案,请发表评论或添加新答案!!