最小限のログを使用して、2つのデータセットを空のヒープテーブルに挿入しました。これは、次の形式のSQLで並列実行される2つのSQL実行タスクを使用して行われました。
INSERT INTO Table (TABLOCK) SELECT FROM ...
ジョブが少しハングした後、SQLタスクの1つがデッドロックの犠牲になりました。以下は、デッドロックグラフのXML出力です。
誰かが内部で何が起こっていたか説明できますか?
<resource-list>
<objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
<owner-list>
<owner id="process9609dc8" mode="Sch-S"/>
<owner id="process9609dc8" mode="IX"/>
</owner-list>
<waiter-list>
<waiter id="process5e13048" mode="X" requestType="convert"/>
</waiter-list>
</objectlock>
<objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
<owner-list>
<owner id="process5e13048" mode="Sch-S"/>
<owner id="process5e13048" mode="IX"/>
</owner-list>
<waiter-list>
<waiter id="process9609dc8" mode="X" requestType="convert"/>
</waiter-list>
</objectlock>
</resource-list>
ほとんどの場合、2つのSQL実行タスクは正常に並行して実行できることがわかったので、事態はかなり複雑になります。以下をお試しください:
Create table dbo.TablockInsert (c1 int, c2 int, c3 int)
--then issue the script in two Execute Sql Task in parallel you won't fail:
insert into dbo.TablockInsert(TABLOCK) SELECT 1, 1, 1
唯一の違いはSELECT ... FROM ...ステートメントであるため、SELECT ... FROM ...ステートメントがロックモードに影響を与える可能性があるように見えますか?
データロードパフォーマンスガイド はSQL Server 2008用に作成されましたが、私の知る限り、Microsoftはこの領域でヒープの改善を行っていません。以下は、ロードシナリオの見積もりです。
空のパーティション化されていないテーブルの一括読み込み
分割されていないテーブルへのデータのロードは、簡単な操作ですが、いくつかの方法で最適化できます。
...
ヒープに対する複数の同時挿入操作は、選択された一括メソッドがテーブルに対して一括更新(BU)ロックを発行する場合にのみ可能です。 2つの一括更新(BU)ロックは互換性があるため、2つの一括操作を同時に実行できます。
このシナリオでは、INSERT…SELECTとSELECT INTOの両方に欠点があります。これらの操作は両方とも、宛先で排他(X)のテーブルレベルロックを取得します。つまり、一度に実行できる一括読み込み操作は1つだけであり、スケーラビリティが制限されます。ただし、TABLOCKヒントを指定した場合、BCP、BULK INSERT、およびIntegration Servicesはすべて、一括更新(BU)ロックを取得できます。
重要な部分は、INSERT ... SELECT
でBUロックを取得しないことです。テーブルには常に排他ロックがかかるため、一度に実行できるINSERT
は1つだけです。
コメントで、10万行以下を挿入し、挿入中に他のプロセスがテーブルで実行されないことを述べました。 2つのINSERTクエリをデータベースに送信すると、次の3つのうちの1つが発生すると予想されます。
いずれの場合も、クエリにTABLOCKX
ヒントを追加することでメリットが得られるか、害を受けないので、デッドロックを回避することをお勧めします。デッドロックが発生することがある理由を知りたい場合は、別の答えを探す必要があります。
並列挿入が本当に必要な別のシナリオでは、BUの問題を回避する2つの方法は、ヒープをパーティション分割して、各セッションを個別のパーティションに挿入するか、BCP、BULK INSERT、または統合サービスを介してデータをロードすることです。 。
2つのセッションからdbo.TargetTable
に挿入し、どちらもTABLOCK
hintを使用しています。process9609dc8
およびIX
ロックを保持しているprocess5e13048
およびSch-S
プロセスの両方これらは互いに互換性があるため、両方のプロセスを同時に保持できます。しかし、どちらもIX
ロックをExclusive X
タイプに変換したいと考えています。 X
ロックは互いに互換性がありません。したがって、SQLサーバーは、互いに無限に待機するのではなく、デッドロックの犠牲者としてセッションの1つを選択しました。