我在运行sql存储过程时遇到问题(MSSQL 2005)。这是它的代码:
CREATE PROCEDURE [GetItemColors]
@FetchCount int
AS
BEGIN
SELECT
TOP (@FetchCount) item.Id as ItemId, item.Published as Published, attributeValue.String as Color
FROM tblItem item, tblAttribute attributeValue, tblAttributeDefinition attributeDef
WHERE
item.Id = attributeValue.fkItemId
AND item.Deleted = 0
AND item.PendingPublish = 0
AND attributeValue.fkAttributeDefinitionId = attributeDef.Id
AND attributeDef.[Name] = 'Color'
ORDER BY item.Published DESC
END;
有时,程序的执行以例外结束:
SqlException: Transaction (Process ID 66) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
有谁知道如何重写程序以避免异常?
在存储过程调用中是否存在“预锁定”表,因此其他代码不能中断执行?
先谢谢你的帮助!
编辑1:附加的估计执行计划
编辑2:我无法获取死锁图,因为异常仅在实时环境中每天发生几次。我不允许在实时环境中运行探查器。我无法在开发环境中重现死锁。
编辑3:我没有成功获得僵局。
答案 0 :(得分:3)
您的执行计划具有不少于3个聚簇索引扫描。使用计划的图片而不是实际计划,我们无法说明运算符的实际属性是什么,但这些行看起来很厚(表示大的结果)并且它们落后于并行运算符。所有这些都指向导致表扫描的错误索引策略。此类大型扫描保证与任何更新冲突。当冲突导致死锁(通常由于索引更新顺序而发生)时,作为只读操作的此查询将始终被选为受害者广告。
一种解决方案是正确索引数据库,以便不再进行那些昂贵的表扫描。除了整体性能优势外,它还可以降低死锁冲突的可能性。
如果死锁仍然存在,那么答案将非常具体,具体取决于实际的死锁情况。
对于一个神奇的“预锁定”策略,你可以拿一把大锤并用或者TABLOCK甚至TABLOCKX提示来装饰你的查询,但性能会很快消失。正确的解决方案是解决死锁问题,而不是强制序列化。