6

とりわけ、ループ内の別のテーブルにいくつかの挿入を行うストアド プロシージャがあります。より明確に理解するために、以下の例を参照してください。

INSERT INTO T1 VALUES ('something')

SET @MyID = Scope_Identity()

... some stuff go here

INSERT INTO T2 VALUES (@MyID, 'something else')

... The rest of the procedure

これらの 2 つのテーブル (T1 と T2) には、それぞれに IDENTITY(1, 1) 列があります。ID1 と ID2 と呼びましょう。しかし、実稼働データベース (非常にビジーなデータベース) で手順を実行し、各テーブルに 6250 を超えるレコードがあった後、ID1 が ID2 と一致しない 1 つのインシデントに気付きました! 通常、T1 に挿入されたレコードごとに、T2 に挿入されたレコードがあり、両方の ID 列が一貫してインクリメントされます。

「間違った」レコードは次のようなものでした。

ID1     Col1
----    ---------
4709    data-4709
4710    data-4710

ID2     ID1     Col1
----    ----    ---------
4709    4710    data-4710
4710    4709    data-4709

2 番目の表の「反転された」ID1 に注意してください。

操作の下にあるSQL Serverについてあまり知らないので、次の「理論」を入れました。誰かがこれを修正してくれるかもしれません。

私が思うに、ループはテーブルへの物理的な書き込みよりも高速であり、および/またはおそらく他の何かが書き込みプロセスを遅らせたため、レコードはバッファリングされました。それらを書く時が来ると、それらは順不同で書かれました。

いいえ、上記のシナリオを説明する方法はありますか?

はいの場合、別の質問があります。最初の挿入 (上記のコードから) が遅れた場合はどうなりますか? それは、2 番目のテーブルに挿入する正しい IDENTITY を取得できないということではないでしょうか? この答えも「はい」の場合、2 つのテーブルへの挿入が正しい IDENTITY で順番に行われるようにするにはどうすればよいでしょうか?

これを理解するのに役立つコメントや情報に感謝します。

前もって感謝します。

4

6 に答える 6

3

2番目のテーブルでこれを解決するためにIDENTITYに依存する方法はありません。その行に対して生成された主キー値が気になる場合は、それ自体を生成する必要があります。

IDENTITYは、「自分でキーを生成する手間をかけたくないので、自分で実行するだけで、必要に応じて生成された値を要求する」という言い方です。

ここで発生する可能性があるのは、2つのスレッドが同時に行を挿入していて、いずれもまだコミットされていないため、次のシナリオが発生する可能性があります。

Thread 1                      Thread 2
get id for table 1 = 4709
                              get id for table 1 = 4710
insert row for table 1
                              insert row for table 1
                              get id for table 2 = 4709
get id for table 2 = 4710
                              insert row for table 2
insert row for table 1

問題を解決するには、次の2つの方法があります。

  1. 2番目のテーブルの主キーのIDENTITYを削除します
  2. SET IDENTITY_INSERT ONIDENTITY設定を維持しながら、キーを提供できるようにするために使用します

ただし、この場合、メソッドnbrを使用します。1.メソッドnbr。2は通常、空のテーブルにデータをインポートするときに使用されます。データベースが後で自分で使用したいIDを自動生成するリスクを望まないので(最初のテーブルからのものであるため)、2番目のテーブルの主キーのIDENTITY設定を無効にする必要があります。

または、外部キー参照があるため、そのテーブルのキーにまったく依存しないようにすることもできます。キー値が本当に同じである必要がありますか?

于 2010-03-15T10:26:31.377 に答える
3

もちろん、上記のシナリオは可能です-そしておそらくそうです。

2つの別個の独立したテーブルがあり、両方がクエリと挿入に使用され、両方が別個のIDENTITY(1,1)フィールドを持つ場合、1つのテーブルへの挿入と2番目のテーブルへの挿入が同じで実行される保証はまったくありません。注文!

2つの間にリンクを確立する必要がある場合は、最初のテーブルのIDを外部キーとして2番目のテーブルに挿入します。IDENTITYから生成されたIDが両方のテーブルで同じであると信頼することはできません。

于 2010-03-15T10:28:34.597 に答える
1

執筆に関して:

  • データを変更する何かを行うときはいつでも、これはその瞬間にデータベースLOGSに書き込まれ、これが行われるまでトランザクション確認を取得しません。これがACID条件のDです(データベース理論)。
  • ダーティなデータベースページは「バックグラウンドで」ディスクに書き込まれます。ダーティが多すぎると、チェックポイントがトリガーされ、すべてダンプされます。

これまでのところ、執筆部分まで。

おそらく遭遇するのは、個々のステートメントはアトミックですが、ビジー状態のatabaseにはおそらく複数のスレッドが実行されているという事実です。したがって、基本的に、ステートメント間でスレッドの切り替えが発生しました。1つのスレッドがId1、別の1つの優先度、id1、id2、次に最初のスレッドがid2を取得しました。

ここでは特に何もありません;)複数のスレッドが実行されている場合の一般的な通常のデータベースの動作。書くこと自体とは何の関係もありません。

基本的に、SET @MyID = Scope_Identity()と次のステートメントの間で、別のスレッドが優先順位を取得できます;)

于 2010-03-15T10:26:36.183 に答える
0

ビジネス/アプリケーションロジックのID列の実際の値に依存しないでください。それらが一意であると想定することしかできません!

于 2010-03-15T13:23:59.523 に答える
0

SQL 2005 の機能である OUTPUT 句を使用すると、この問題を回避できるはずです。以下のリンク。

http://msdn.microsoft.com/en-us/library/ms177564.aspx

于 2010-03-15T17:19:04.543 に答える
-1

これは、SQL Server の既知のバグです。

問題は、クエリ プランを生成するときに、並列処理によってスコープ ID が正しくなくなることです。

その部分を独自のプロシージャに移動して、params を渡し、スコープ ID を返します。これで正しいはずです。

私の記憶が正しければ、これは約 100 万行以上のテーブルでのみ現れます。

KB はこちら: http://support.microsoft.com/default.aspx?scid=kb;en-us;2019779&sd=rss&spid=2855

于 2010-03-15T13:44:05.680 に答える