5

执行此存储过程时出现死锁:

-- Delete transactions
delete from ADVICESEQUENCETRANSACTION
where ADVICESEQUENCETRANSACTION.id in (
  select TR.id from ADVICESEQUENCETRANSACTION TR
  inner join ACCOUNTDESCRIPTIONITEM IT on TR.ACCOUNTDESCRIPTIONITEMID = IT.id
  inner join ACCOUNTDESCRIPTION ACC on IT.ACCOUNTDESCRIPTIONID = ACC.id
  inner join RECOMMENDATIONDESCRIPTION RD on ACC.RECOMMENDATIONDESCRIPTIONID = RD.id
  inner join RECOMMENDATION REC on REC.id = RD.RECOMMENDATIONID
  inner join ADVICESEQUENCE ADV on ADV.id = REC.ADVICESEQUENCEID
  where adv.Id = @AdviceSequenceId AND (@RecommendationState is NULL OR @RecommendationState=REC.[State])
    );

这是表的架构:

表的架构

这是死锁图:

在此处输入图像描述

您可以在此处查看死锁图的详细信息

因此,当我检索 ressource 节点的 associatedobjid 时,我确定它是表 AdviceSequenceTransaction 的主键和索引:

SELECT OBJECT_SCHEMA_NAME([object_id]), * ,
OBJECT_NAME([object_id]) 
FROM sys.partitions 
WHERE partition_id = 72057595553120256 OR partition_id = 72057595553316864;

SELECT name FROM sys.indexes WHERE object_id = 31339176 and (index_id = 1 or index_id = 4)

PK_AdviceSequenceTransaction IX_ADVICESEQUENCEID_ADVICE

由于在键 ParentTransactionId 和键主键上的表 AdviceSequenceTransaction 上存在关系,因此我在 ParentTransactionId 列上创建了一个索引。

我没有更多的死锁。但问题是我不知道为什么没有更多的死锁:-/

而且,在测试它的数据集上,ParentTransactionId 中没有数据。都是NULL。

因此,即使 ParentTransactionId 中没有数据(null),SQL Server 是否可以访问主键???

另一件事是我想删除删除语句中的连接:

delete from ADVICESEQUENCETRANSACTION
where ADVICESEQUENCETRANSACTION.id in (
  select TR.id from ADVICESEQUENCETRANSACTION TR
  inner join ACCOUNTDESCRIPTIONITEM IT on TR.ACCOUNTDESCRIPTIONITEMID = IT.id
  inner join ACCOUNTDESCRIPTION ACC on IT.ACCOUNTDESCRIPTIONID = ACC.id
  inner join RECOMMENDATIONDESCRIPTION RD on ACC.RECOMMENDATIONDESCRIPTIONID = RD.id
  inner join RECOMMENDATION REC on REC.id = RD.RECOMMENDATIONID
  inner join ADVICESEQUENCE ADV on ADV.id = REC.ADVICESEQUENCEID
  where adv.Id = @AdviceSequenceId AND (@RecommendationState is NULL OR @RecommendationState=REC.[State])
    );

进入 :

delete from ADVICESEQUENCETRANSACTION
where ADVICESEQUENCETRANSACTION.id in (
  select TR.id from ADVICESEQUENCETRANSACTION TR
  inner join ACCOUNTDESCRIPTIONITEM IT on TR.ACCOUNTDESCRIPTIONITEMID = IT.id
  inner join ACCOUNTDESCRIPTION ACC on IT.ACCOUNTDESCRIPTIONID = ACC.id
  inner join RECOMMENDATIONDESCRIPTION RD on ACC.RECOMMENDATIONDESCRIPTIONID = RD.id
  inner join RECOMMENDATION REC on REC.id = RD.RECOMMENDATIONID
  where TR.AdviceSequenceId = @AdviceSequenceId AND (@RecommendationState is NULL OR @RecommendationState=REC.[State])
    );

我删除了最后一个加入。但是如果我这样做,我又会陷入僵局!又来了,不知道为什么...

谢谢你的启发:)

4

2 回答 2

2

在 WHERE 子句中使用复杂的复合连接通常会导致问题。SQL Server 使用以下逻辑处理顺序处理子句(在此处查看):

  1. 加入
  2. 在哪里
  3. 通过...分组
  4. WITH CUBE 或 WITH ROLLUP
  5. 拥有
  6. 选择
  7. 清楚的
  8. 订购方式
  9. 最佳

使用视图或派生表或视图可大大减少获得所需结果所需的迭代 (TABLE) 扫描次数,因为查询中的重点更好地对齐以使用逻辑执行顺序。每个派生表(或视图)的 FROM 子句首先执行,限制传递给 ON 原因的结果集,然后是 JOIN 子句等等,因为您将参数传递给“内部 FROM”而不是“最外面的地方”。

所以你的代码可能看起来像这样:

delete from (SELECT   ADVICESEQUENCETRANSACTION
             FROM     (SELECT tr.id 
                      FROM ADVICESEQUENCETRANSACTION WITH NOLOCK
                      WHERE AdviceSequenceId = @AdviceSequenceId
                      )TR
            INNER JOIN (SELECT [NEXT COLUMN]
                        FROM [NEXT TABLE] WITH NOLOCK
                        WHERE COLUMN = [PARAM]
                        )B
            ON        TR.COL = B.COL            
            )ALIAS
            WHERE [COLUMN] = COL.PARAM
);

依此类推...(我知道代码不能剪切和粘贴,但它应该可以传达总体思路

通过这种方式,您首先将参数传递给“内部查询”,预加载有限的结果集(特别是如果您应该使用视图),然后向外工作。在适当的地方使用锁定提示也将有助于防止您可能遇到的一些问题。如果您还有任何块,这种技术还可以帮助您更有效地帮助您诊断块来自哪里的执行计划。

于 2013-11-13T12:02:06.240 回答
0

如果您不介意脏读,一种方法是在表 ADVICESEQUENCETRANSACTION TR 上使用 WITH (nolock)。

于 2013-10-20T23:18:48.797 回答