2011-10-26 15 views
3

以下のデッドロックグラフに表示されるデッドロックの状況に関連する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

EDIT

ここここ更新クエリ(工程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 

それはSELECTクエリ(工程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

このプロシージャをどのように呼びますか?私は "BEGIN TRAN"ステートメントが表示されないので、SqlTransactionコンテキスト内でこれを実行しているかどうかは疑問です。 – sarme

+0

はいADO.NETによって開かれたトランザクションコンテキスト内では、updateOrderDetailsが呼び出されます。 –

答えて

1

最後に、呼び出しコードの問題であることが判明しました。説明するのは難しいですが、基本的に取引が開かれ、いくつかの方法に引き渡されました。

トランザクションを削除し、デッドロックがなくなりました。

もちろん、トランザクションを再度実装して、トランザクション処理の実装方法やトランザクションの長さが長すぎるかどうかを確認する必要があります。

+0

さて...楽しんでください。私は、コードを知っていると思う... :) –

3

でありますそれぞれのプロセスに関連するステートメントを投稿できる場合に役立ちますが、ここでは...

SELECTステートメントが集計を行っている場合、テーブルロックを取得できます。ユースケースが許せば、WITH(NOLOCK)ヒントを試してみることもできます。

UPDATEステートメントは、実際に変更されるレコードの範囲(つまり、WHERE条件の選択性、およびインデックスの効率的な使用かどうか)に依存します。

関連するテーブルにトリガがある場合は、そのコードも慎重に調べる必要があります。私の経験では、それらはデッドロック状況の最も一般的な原因です。特に、発行された声明が比較的単純であるように見える場合。トリガーが見つかった場合は、それらを使用不可にし、テスト環境で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 

これは、同じ「注文」行のその後の更新は、デッドロックが発生していないことを保証します - 「注文」行がすでにロックされていますトランザクションの開始時に

関連する問題