web-dev-qa-db-ja.com

Microsoft SQL-ServerのSIXロックについて

プロセスがページのSIXロックを取得する方法を誰かに説明できますか?私のデッドロックグラフxmlファイルRC分離レベルで実行されているプロセス(デッドロックの瞬間にselectステートメントを実行)がSIXページのロック。

これはどういう意味で、どのようにしてそのロックを取得できたのでしょうか。私が得たものから http://msdn.Microsoft.com/en-us/library/aa213039%28v=sql.80%29.aspxSIXロックはS- locksはすべてのリソースを対象とし、IX locksは一部のリソースを下位階層に割り当てます。

私の場合、それは行のIX- locksでしょうか? IX- lockを行に配置できますか? (私はそうは思いません)。私は混乱しています。

別のことは、行にいくつかのX- locksがあり、S- locksがまったくないことを期待していることです([〜#〜] il [〜# 〜]isReadCommited)です。前のステートメントでいくつかのレコードのみを挿入した場合、なぜページ全体がSIXでロックされるのですか?

編集:デッドロックxml:

<deadlock-list>
 <deadlock victim="process4df94c8">
  <process-list>
   <process id="process4df94c8" taskpriority="0" logused="2968" waitresource="PAGE: 7:1:181357" waittime="3111" ownerId="41854656297" transactionname="user_transaction" lasttranstarted="2013-06-06T11:09:42.087" XDES="0x1d2434e80" lockMode="IX" schedulerid="6" kpid="3476" status="suspended" spid="52" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2013-06-06T11:09:42.183" lastbatchcompleted="2013-06-06T11:09:42.183" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4260" loginname="cwcuser" isolationlevel="read committed (2)" xactid="41854656297" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="508" stmtend="1358" sqlhandle="0x02000000876d6b08786774c344ce9ce8bd077ccce54751be">
INSERT [WP_CashCenter_StockTransactionLine] ([isverified], [isstockownerchanged], [dateupdated], [quantity], [value], [weight], [qualificationtype], [direction], [material_id], [stockcontainer_id], [stockownerid], [stocktransaction_id]) VALUES (@isverified, @isstockownerchanged, @dateupdated, @quantity, @value, @weight, @qualificationtype, @direction, @material_id, @stockcontainer_id, @stockownerid, @stocktransaction_id);     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@isverified bit,@isstockownerchanged bit,@dateupdated datetime,@quantity int,@value decimal(4,2),@weight decimal(8,8),@qualificationtype int,@direction int,@material_id nvarchar(3),@stockcontainer_id bigint,@stockownerid int,@stocktransaction_id bigint)INSERT [WP_CashCenter_StockTransactionLine] ([isverified], [isstockownerchanged], [dateupdated], [quantity], [value], [weight], [qualificationtype], [direction], [material_id], [stockcontainer_id], [stockownerid], [stocktransaction_id]) VALUES (@isverified, @isstockownerchanged, @dateupdated, @quantity, @value, @weight, @qualificationtype, @direction, @material_id, @stockcontainer_id, @stockownerid, @stocktransaction_id); SELECT scope_identity()    </inputbuf>
   </process>
   <process id="process5cd948" taskpriority="0" logused="24656" waitresource="KEY: 7:72057594277003264 (889d2c878f57)" waittime="3098" ownerId="41854656065" transactionname="user_transaction" lasttranstarted="2013-06-06T11:09:41.970" XDES="0x1253053c0" lockMode="S" schedulerid="3" kpid="4116" status="suspended" spid="59" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2013-06-06T11:09:42.180" lastbatchcompleted="2013-06-06T11:09:42.177" lastattention="2013-06-03T13:13:45.090" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4260" loginname="cwcuser" isolationlevel="read committed (2)" xactid="41854656065" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" sqlhandle="0x020000009e156e12789f4ef811698c627d479b0240c2a7c1">
SELECT * FROM WP_CashCenter_StockTransaction
                WHERE [id] IN (
                    SELECT DISTINCT [ST].[id]
                    FROM WP_CashCenter_StockTransaction AS [ST]
                        LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                    WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 300000274211 OR [ST].[StockContainerID] = 300000274211))     </frame>
    </executionStack>
    <inputbuf>
SELECT * FROM WP_CashCenter_StockTransaction
                WHERE [id] IN (
                    SELECT DISTINCT [ST].[id]
                    FROM WP_CashCenter_StockTransaction AS [ST]
                        LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                    WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 300000274211 OR [ST].[StockContainerID] = 300000274211))    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <pagelock fileid="1" pageid="181357" dbid="7" objectname="Eindhoven_CWC.dbo.WP_CashCenter_StockTransactionLine" id="lock366ad3a80" mode="SIX" associatedObjectId="72057594277265408">
    <owner-list>
     <owner id="process5cd948" mode="SIX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process4df94c8" mode="IX" requestType="wait"/>
    </waiter-list>
   </pagelock>
   <keylock hobtid="72057594277003264" dbid="7" objectname="Eindhoven_CWC.dbo.WP_CashCenter_StockTransaction" indexname="PK_WP_Inbound_StockTransaction" id="lockee362e00" mode="X" associatedObjectId="72057594277003264">
    <owner-list>
     <owner id="process4df94c8" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process5cd948" mode="S" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>
5
Artur Udod

少し回り道をしないといけないので我慢して。

2つのセッションが同じリソースをロックする場合、SQL Serverはロック互換性マップをチェックし、2番目の要求が最初の要求と「互換性がない」場合、2番目のセッションは待機する必要があります。 「S」共有、「U」pdate、e「X」の3つのロックタイプがあります。 Sロックはリソースからの読み取りに使用され、Xロックはリソースへの書き込みに使用されます。 Sロックは互いに互換性があり、Xロックは他のものと互換性がありません。 Uロックは、デッドロック防止のためにいくつかのケースで使用されるハイブリッドです。

現在、SQL Serverは、テーブル、パーティション、ページ、行などのいくつかのレベルでロックを取得できます。したがって、セッション1がテーブルロックを取得し、セッション2がテーブルの1行で互換性のないロックを取得した場合、これら2つのロックは同じリソース上になく、SQL Serverは衝突を検出しません。これを防ぐために、SQL Serverは常にテーブルレベルでロックを取得し始め、階層を下っていきます。現在、ページと行のロックのポイントは同時実行性が高いため、あるセッションが1つの行に書き込み、別のセッションが別の行に書き込みたい場合、それらは互いにブロックすべきではありません。行のロックを取得するだけでなく、セッションもテーブルの同じロックを取得する必要がある場合、その利点はなくなります。そのため、テーブルで排他ロック(X)を取得する代わりに、セッションは意図的排他ロック(IX)を要求します。このロックは他の意図的なロックと互換性がありますが、他の「実際の」ロックとは互換性がありません。したがって、別のセッションが同じテーブルに対して意図的排他ロックを取得することもできます。意図的排他ロックは、セッションが下位レベルのリソースで排他的ロックを取得しようとしていることを示しています。意図されたロックが行ロックである場合、ページレベルでも同じことが起こります。そのため、すべてが行われた後、セッションはテーブルとページの1つにIXロックを持ち、そのページの行の1つにXロックを持ちます。 。これは、行がロック階層の最下位レベルであるため、行の意図したロックが見つからないことも意味します。

状況によっては、セッションがテーブルまたはページにSロックを保持します。 (同じトランザクション内の)セッションが同じテーブルの行にXロックを要求する場合、最初にテーブル/ページのIXロックを取得する必要があります。ただし、セッションは特定のリソースに対して1つのロックしか保持できません。したがって、IXロックを取得するには、Sロックを解放する必要があるため、おそらく望ましくないため、SQL ServerはSIXの組み合わせを提供します。

ページロックがある理由は、SQL Serverが、各行をロックするよりもページをロックする方が適切であると判断する場合があるためです。これは、すでにすべてのセッション間で非常に多くのロックがかけられている場合によく発生しますが、他にも多くの理由が考えられます。

これまでのところ、理論。

これで、SIXロックは3つのテーブルの結合選択クエリによって保持されます。 selectは、明示的に(XLOCKヒントなどを使用して)指示しない限り、共有ロックではないタイプのロックを取得することはありません。このようなヒントは入力バッファー内では表示されないため、IX部分は、この接続の最後のバッチからの残りであると想定しています。接続プールを使用していて、開いているすべてのトランザクションをクリーンアップするのを忘れている場合、そのようなロックは永久に存続する可能性があります。しかし、トラブルシューティングも非常に難しくなります。

まず、OPEN TRANとCOMMITをペアにするXEventセッションを実行し、その方法で原因を見つけることができるかどうかを確認します。

17
Sebastian Meine