1

この問題は、同時高速挿入に関するものです。私はそれが私の目に非常に興味深いことを認めなければなりません。

私は SQL Server 2008 R2 を使用して T-SQL 挿入を実行し、挿入トリガーを実行しています。

挿入と挿入後のトリガーの間でコマンドが実行されないようにしたいと思います。

分離レベルを使用すると、デッドロックが発生するか、問題が解決されません。

私が使用している手順は、Phil から SQL Server に依存する Identity への回答/解決策です。そのようなことはありますか?

問題は:

前の挿入とその挿入後のトリガーの間に挿入が入り、次のような結果になることがあります。

RoomID  ItemID  ItemDescription ID
------  ------  --------------- --
7       1       Door             1
7       2       Window (West)    2
7       3       Window (North)   3
8       1       Door             4
8       2       Table #1         5
8       3       Table #2         6
7       4       Table #1         7
8       4       Chair #1         8
7       6       Table #2         9
7       5       Table #3        10
8       5       Chair #2        11

ID #9 と #10 を参照してください。タイの ItemID が入れ替わっています。ItemID は、6 と 5 ではなく、それぞれ 5 と 6 である必要がありますが、10 番目の挿入は、#9 の after insert トリガーが実行を終了する前に発生した可能性があります。

この問題は、挿入の 0.5% 未満で発生します: 1000 以下の挿入に対して 4 つのレコードを含む 2 つの切り替え。はい、スイッチが発生しない場合もあります。

分離レベルを 1 段階上げても効果はなく、場合によってはより多くのキー/依存キーの切り替えが発生することさえあります。分離レベルを 2 つ上げると、デッドロックが発生しました。

分離レベルを下げるとスイッチは減りますが、それでも作成されます。

すべての挿入の前に高い分離レベルを開始し、トリガーの最後にデフォルトの分離レベルに戻すと、デッドロックが発生します (私の実験では、すべての挿入がコミットされませんでした!)。

誰かが抜け道を見ていますか?

挿入と挿入後のトリガーを強制的に一緒に実行し、その間に同じテーブルへの他の挿入を禁止する方法は?

4

1 に答える 1

5

挿入トリガーの代わりに使用するのはどうですか?

もちろん、実際の挿入は自分で行う必要がありますが、それは SQL Server でサポートされている動作です。before insert トリガーなどはありません。

とにかく、このタイプのトリガーでも現在のトリガー処理ロジックを引き続き使用できます。

より良い解決策を想像するために、何をしようとしているのか説明できますか? 複数のスレッドがこのテーブルに挿入されていますか? これはリアルタイムのプロセスですか?

まるでオークション。はい、複数のスレッドがこのテーブルに挿入されています。問題は後部ですが、起こります。苦情の理由はまだありませんが、あるかもしれません (スイッチは今までに臨界点ではありませんでした)。挿入を開始するユーザーは、注文リストでの優先順位を知る必要があります。ItemID はほぼ差し迫って使用されるため、数ミリ秒後に必要になったときにその場で (select count(*)... where.. を使用して) 計算されない場合があります。ItemID の順序を間違えると、一方が損失を被り、他方が不当に利益を得る可能性があります。

まあ、マルチスレッドの挿入は、SQL サーバーではほとんど良い考えではありません。少なくとも、ある種の同期がないわけではありません。

ある種の待ち行列が必要です。たとえば、1 日あたり 250 万から 300 万のレコードを挿入する必要がある同様のシステムがあります (まあ、労働時間)。

最初は、データベースに直接挿入するために 8 ~ 16 のスレッドも使用していました。そして、まさにこの動作に気付きました: デッドロックです。そこで、いつでも 1 つのスレッド (1 つの接続) だけが挿入されるように、これらのメッセージをキューに入れる方法を考え始めました。

これらのレコードを MSMQ (トランザクション) でキューに入れることになりました。他のプロセスが来て、ここからそれらを取得し(これもトランザクション)、データベースにバッチで挿入します。私の記録は、送信されたときの正しい順序で届くことが保証されています。

したがって、この 2 次プロセスはレコードのバッチを挿入します。あなたのように、挿入する前にいくつかの前処理が必要です。これは、insert-of-insert トリガーを使用して行っています。そこでは、テーブル全体をinserted「静かに」更新できます。誰かが来て私のものを台無しにすることを心配する必要はありません。

それはただのアイデアです。また、特に SQL Server の外部で処理を行いたくない場合は、キューイングに Service Broker を検討することもできます。

また、試してみる価値があるのは、スナップショット分離レベルと行のバージョン管理を使用したトランザクションですが、MSMQ/サービス ブローカーの方法をお勧めします。

于 2012-06-29T15:37:32.853 に答える