6

SQL Server 2008 のデッドロック グラフを使用して、SQL サーバーのデッドロックの問題を診断しました。

問題は私のインデックスに関係しています。2 つのクエリがあります。ベース テーブルの 2 つの異なる日付に従ってデータを取得する多数の結合とサブクエリを含む長期実行レポートと、そのベース テーブルの同じ日付を更新するクイック更新クエリです。2 つのインデックスがあり、レポートは両方に共有 KEY ロックを必要としますが、更新クエリはそれらの両方に排他的 KEY ロックを必要とし、どういうわけか各クエリはキーの 1 つしか取得できないため、どちらも続行できません。

これを修正するにはどうすればよいですか?

ここに私の状況に関するすべての詳細があります:

私のベーステーブルは次のようになります。

CREATE TABLE job_tb{
    job_id int IDENTITY(1,1),
    createDate datetime NULL,
    upDate datetime NULL,
    dataField1 nchar(1),
    dataField2 nchar(2),
    --etc...
}

私のインデックスは次のようになります。

CREATE NONCLUSTERED INDEX idx_createDate ON job_tb(
  createDate DESC
)
INCLUDE(dataField1, dataField2)

CREATE NONCLUSTERED INDEX idx_upDate ON job_tb(
  upDate DESC
)
INCLUDE(dataField1, dataField2)

最後に、私の更新は次のようになります。

BEGIN TRANSACTION;
    UPDATE job_tb
    SET
        dataField1 = @data
        upDate = @upDate
    WHERE
        job_id = @job_id
COMMIT TRANSACTION;

また、このレポートはあらゆる種類の統計を日付別にカウントしているため、ここには含めません。idx_createDate と idx_upDate は、そのレポートで頻繁に使用されているため、dataField1 を「カバー」または含めるように意図的に設計しました。

レポートは、インデックスの 1 つで共有ロックを取得し、サブクエリにヒットして、2 番目のインデックスでロックを要求していると思います。一方、更新クエリは、upDate と含まれる dataField1 の両方を更新するために、両方のインデックスを排他的にロックする必要があります。

皆さんはどう思いますか?

編集: 要求された XML デッドロック グラフは次のとおりです。

<deadlock-list>  <deadlock>
<victim-list>
    <victimProcess id="processcf65288"/>
</victim-list>
<process-list>
    <process id="processcf65288" taskpriority="0" logused="0" waitresource="KEY: 6:72057597970874368 (eee1799e706c)" waittime="122" ownerId="421742704" transactionname="SELECT" lasttranstarted="2012-08-03T05:37:21.257" XDES="0x8611e8800" lockMode="S" schedulerid="50" kpid="8560" status="suspended" spid="70" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2012-08-03T05:37:21.257" lastbatchcompleted="2012-08-03T05:37:21.257" clientapp="Internet Information Services" hostname="xxx" hostpid="11964" loginname="xxx" isolationlevel="read committed (2)" xactid="421742704" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
        <executionStack>
            <frame procname="" line="28" stmtstart="1276" stmtend="4826" sqlhandle="0x03000600311ac36c65a31701a1a000000100000000000000">
            </frame>
            <frame procname="" line="1" sqlhandle="0x01000600f61bee3600932ae3090000000000000000000000">
            </frame>
        </executionStack>
        <inputbuf> exec MonthlyReport @id = 41
        </inputbuf>
    </process>
    <process id="processd2b6bc8" taskpriority="0" logused="1908" waitresource="KEY: 6:72057597970939904 (8e8117a49479)" waittime="2242" ownerId="421742551" transactionname="user_transaction" lasttranstarted="2012-08-03T05:37:20.447" XDES="0x7e84ad0a0" lockMode="X" schedulerid="63" kpid="12700" status="suspended" spid="89" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2012-08-03T05:37:20.443" lastbatchcompleted="2012-08-03T05:37:20.443" clientapp="Internet Information Services" hostname="xxx" hostpid="11964" loginname="xxx" isolationlevel="read committed (2)" xactid="421742551" currentdb="6" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
        <executionStack>
            <frame procname="" line="47" stmtstart="2342" stmtend="2640" sqlhandle="0x03000600e7dd9c717cbbb900ec9f00000100000000000000">
            </frame>
            <frame procname="" line="1" sqlhandle="0x01000600311d7a152032f9be040000000000000000000000">
            </frame>
        </executionStack>
        <inputbuf> exec UpdateJob @dataField1 = &apos;C&apos;, @upDate = &apos;8/3/2012 5:37:20 AM&apos;, @job_id = 1542687
        </inputbuf>
    </process>
</process-list>
<resource-list>
    <keylock hobtid="72057597970874368" dbid="6" objectname="" indexname="" id="lock612859900" mode="X" associatedObjectId="72057597970874368">
        <owner-list>
            <owner id="processd2b6bc8" mode="X"/>
        </owner-list>
        <waiter-list>
            <waiter id="processcf65288" mode="S" requestType="wait"/>
        </waiter-list>
    </keylock>
    <keylock hobtid="72057597970939904" dbid="6" objectname="" indexname="" id="lock612a15300" mode="S" associatedObjectId="72057597970939904">
        <owner-list>
            <owner id="processcf65288" mode="S"/>
        </owner-list>
        <waiter-list>
            <waiter id="processd2b6bc8" mode="X" requestType="wait"/>
        </waiter-list>
    </keylock>
</resource-list>  
</deadlock> /deadlock-list> 
4

1 に答える 1

6

コメントでのQ/Aの議論に基づいて、デッドロックグラフを分析した後、これは、レポートクエリが現在の2つのインデックスで完全にカバーされていない場合です。レポートは、最初に非クラスター化インデックスの調査を開始します。必要な情報がすべて見つかりません。したがって、残りのデータを取得するためにプライマリテーブルでキールックアップを実行します。ただし、更新はまったく逆の方法で機能します。更新では、最初にプライマリテーブルがロックされ、そのデータが更新されてから、すべてのインデックスが更新されます。したがって、デッドロック。

これを修正する1つの方法は、レポートクエリ全体をインデックスでカバーすることです。ただし、これには更新が遅くなるという意味があります。

他の解決策は、レポートクエリを2つに分割し、一時テーブル変数を使用してインデックスからデータを収集してから、キールックアップを実行することです。レポートクエリは、シリアル化可能なトランザクションモードでは実行しないでください。そうしないと、トランザクションは読み取ったばかりの読み取りロックを解放しません。

はっきりしているといいのですが。ご不明な点がございましたら、お気軽にお問い合わせください。

于 2012-08-03T18:18:30.650 に答える