我有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>
修改
这是更新查询(流程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
答案 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
这可确保相同“订单”行的后续更新不会导致死锁 - “订单”行在交易开始时已被锁定。