我怎样才能摆脱这种僵局?

时间:2011-10-26 13:04:46

标签: sql-server deadlock

我有2个查询涉及下面死锁图中显示的死锁情况。 (Seitensperre表示分页)

进程55中的查询是死锁牺牲品。这是一个包括表格订单和付款的选择。

进程95上的查询中有几个查询 在开始时,ist会做一些选择将一些值存储到变量中(访问表顺序) 然后它会更新表格顺序并在表格付款之后。

我不明白这种情况会导致死锁。你能解释一下僵局造成了什么以及我能做些什么吗?我想我只是很难阅读死锁图。

以下是所涉及的资源。

<resource-list>
   <objectlock lockPartition="0" objid="1104059019" subresource="FULL" dbid="9" objectname="mycompany.dbo.order" id="lock1b9596980" mode="S" associatedObjectId="1104059019">
    <owner-list>
     <owner id="process443bac8" mode="S"/>
    </owner-list>
    <waiter-list>
     <waiter id="process20fc5eda8" mode="IX" requestType="wait"/>
    </waiter-list>
   </objectlock>
   <pagelock fileid="1" pageid="1825971" dbid="9" objectname="mycompany.dbo.Payment" id="lock1bca33000" mode="IX" associatedObjectId="72057594063159296">
    <owner-list>
     <owner id="process20fc5eda8" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process443bac8" mode="S" requestType="wait"/>
    </waiter-list>
   </pagelock>
  </resource-list>

enter image description here

修改

这是更新查询(流程95)

ALTER   PROCEDURE [dbo].[updateOrderDetails]
(
    @id_order               int,
    @customerComment        NText,
    @salutationBilling      nvarchar(50) = '00',
    @companyNameBilling     nvarchar(100)= ''

        ...some more Parameters
)
AS
DECLARE @user_change int, @id_orderAddress int,
        @id_voucherType int, @id_orderPayment int, @id_paymentMode int


SET NOCOUNT ON;
SET ANSI_NULLS ON

SELECT @user_change = 0
SELECT @id_orderAddress = 0
SELECT @id_voucherType = 0
SELECT @id_orderPayment = 0
SELECT @id_paymentMode = 0


SELECT @user_change = id FROM user
 WHERE logonName = @user_str

SELECT @id_orderAddress = id_orderAddress FROM order
 WHERE [id] = @id_order

SELECT @id_voucherType = [id] FROM voucherType
 WHERE [name] = @voucherTypeName


SELECT @id_orderPayment = [id_orderPayment] FROM order 
 WHERE [id] = @id_order 

SELECT @id_paymentMode = [id] FROM paymentMode
 WHERE [name] = @paymentModeName


IF @user_change = 0 GOTO ERR
IF @id_voucherType = 0 GOTO ERR

UPDATE order
SET
[id_voucherType]        =       @id_voucherType,
[customerComment]       =       @customerComment,
[causeOfCancellation]   =       @causeOfCancellation
...some more fields to update

WHERE
[id] = @id_order

IF @id_orderAddress = 0 GOTO ERR

UPDATE Address
SET
[salutationBilling]     =    @salutationBilling,
[companyNameBilling]    =    @companyNameBilling,
[firstNameBilling]      =    @firstNameBilling
...some more fields to update
WHERE
[id] = @id_orderAddress

IF @id_orderPayment = 0 OR @id_paymentMode = 0 GOTO ERR
UPDATE Payment
SET
[id_paymentMode]        =   @id_paymentMode,
[customerBankDepositor] =   @customerBankDepositor,
[customerBank]          =   @customerBank,
[customerBankCode]      =   @customerBankCode,
...some more fields to update
WHERE
[id] = @id_orderPayment

IF @@Error > 0 Goto ERR


RETURN 0

ERR:

return  -1;
SET QUOTED_IDENTIFIER ON

这是选择查询(过程55)

ALTER  PROCEDURE [dbo].[searchOrders]
(
  @SelectType           INT
 ,@searchB2B            INT
 ,@VoucherNumber        NVARCHAR(50)  = null
 ,@FirstNameBilling     NVARCHAR(100) = null
    ... some more parameters
)

AS

SET NOCOUNT ON;

IF  @SelectType = 0 and LEN(@VoucherNumber) > 0
 BEGIN
    SELECT DISTINCT  (o.id)
                    ,o.voucherNumber
                    ...some more columns

    FROM             order AS o
    LEFT JOIN        orderAssignment AS oa  ON o.id = oa.id_order
    LEFT JOIN        voucherType AS vt      ON o.id_voucherType = vt.id
    LEFT JOIN        Payment AS op      ON o.id_orderPayment = op.id
    LEFT JOIN        paymentMode AS pm      ON op.id_paymentMode = pm.id
    LEFT JOIN        orderAddress AS addr   ON o.id_orderAddress = addr.id
    LEFT JOIN        user AS u1             ON o.user_change = u1.id
    LEFT JOIN        user as u2             ON oa.id_user = u2.id   
    LEFT JOIN        b2bAccount as b2b      ON o.id_b2bAccount = b2b.id


    WHERE            o.voucherNumber like @VoucherNumber
    AND              o.isB2B = @searchB2B
 END
...some more cases depending on @SelectType but the actual query is with @SelectType = 0

RETURN

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON

3 个答案:

答案 0 :(得分:3)

如果您可以发布每个流程中涉及的语句,那将会很有帮助,但这里有...

如果SELECT语句正在进行聚合,则可以获取表锁。如果您的用例允许,您可以尝试使用WITH(NOLOCK)提示。

UPDATE语句实际上取决于被修改的记录范围 - WHERE条件的选择性以及是否有效地使用索引。

如果涉及的表有任何触发器,您还需要仔细检查该代码。根据我的经验,它们是导致死锁情况的最常见原因。特别是当发表的声明在表面上看起来相对简单时。如果找到触发器,请尝试禁用它们并在测试环境中运行这两个语句,以验证它们是否导致死锁。

但最终,无法始终阻止死锁。您最好尽可能地优化您的能力,但始终处理选择一个或两个语句作为受害者并优雅地清理/存在或重试批次的情况。

答案 1 :(得分:1)

最后证明这是调用代码的问题。它很难解释,但基本上是一个交易被打开并移交给几种方法。

我删除了该事务,并且死锁消失了。

当然,我必须再次重新实现该事务,看看它是如何实现事务处理的,或者事务是否跨越了太久。

答案 2 :(得分:0)

在内部交易中,更改

等查询
SELECT @id_orderAddress = id_orderAddress FROM order
 WHERE [id] = @id_order

以下:

SELECT @id_orderAddress = id_orderAddress FROM order WITH(UPDLOCK)
 WHERE [id] = @id_order

这可确保相同“订单”行的后续更新不会导致死锁 - “订单”行在交易开始时已被锁定。