web-dev-qa-db-ja.com

最後のレコードをDBに挿入するためのベストプラクティス

私と数人の同僚が次のケースについて話し合っています。

OrderStatusテーブルでは、_"Pending"_、_"Available"_、_"Returned"_など、注文が時間内に通過するすべてのステータスを追跡しています。タイムスタンプフィールドがあります各ステータスがいつ追加されたかを追跡するために、表にあります。ただし、正確に同時に追加できるステータスが2つあり、その場合、両方のタイムスタンプがまったく同じ(ミリ秒を含む)になる場合があります。コードの別の部分では、注文が設定された最後のステータスを確認する必要があります。タイムスタンプで注文しているため、データベースから間違ったレコードを簡単に取得できます。

テーブルにはIDENTITY(1,1)主キーがあり、同僚はその列を使用して注文する必要があると考えています。これにより、常にテーブルに追加された最新のレコードが必ず得られるからです。

IDENTITY列には何の意味もないので、並べ替えには使用しないでください。タイムスタンプが確実に異なるようにThread.Sleep(1)を実行して、そのフィールドを使用してソートします。

この場合のベストプラクティスは何だと思いますか?

6
Antrim

数値が大きいほど高い状態を表すステータス値を使用します。それを降順でインデックスに追加します。次に、タイムスタンプ順の結果をプルバックしますandステータスを降順で返します。このようにして、最も遠い進行のエントリが常に返されます。

5
GrandmasterB

イベントソーシングアプローチが役立つと思います

http://martinfowler.com/eaaDev/EventSourcing.html

基本的に、オブジェクトを更新するたびに、オブジェクトをロードし、イベントを履歴に追加して、すべてを保存します。

オブジェクトを保存するとき、その間に履歴が更新されていないことを確認します。持っている場合は、新しい履歴からオブジェクトを再構築し、イベントの追加を再試行します

または、オブジェクトをロックして、他のイベントが終了するまで待機させることもできます。

これは、イベントが順序で保存されるだけでなく、順序どおりに処理されることを保証するため、auto-inc列などよりも優れています。

しかし、あなたの特定のケースでは、あなたのステータスは発生したイベントの関数であるように私には思えます。最後のイベントからステータスを読み取らせる代わりに、発生したすべてのイベントに基づいて計算を行います。

この場合、どちらのイベントが最初に発生したか、または2つが同時に発生したかは問題ではありません。

すなわち

「注文が選択されました」と「顧客の信用調査に合格した」と言います

概念的には、これらの両方が同時に発生する可能性がありますが、ステータスは

「未選択」-未選択のイベント

「保留中の信用調査」-選択されたイベントが信用調査イベントなし

「配達準備完了」-選択され、かつ信用調査済み

1
Ewan

より良い方法は、2つのテーブルを最新のものと履歴として保持することです。現在のテーブルは常に最新の更新になります。もう1つのテーブルは、常に挿入と読み取りだけの履歴テーブルです。最新のレコードを取得する場合は、現在のテーブルをクエリします。ダーティリードを許可しない場合は、常に最新のレコードになります。履歴が必要な場合は、履歴テーブルをクエリし、PKで並べ替えます。

現在のテーブルでは、タイムスタンプを保持したいので、誰かが読み取り後にレコードを更新した場合、更新を行う前に競合を適切に処理できます。履歴テーブルでは常に挿入しているため、チェックは必要ありません。必要に応じて、現在のテーブルからトリガーを使用して履歴の挿入を処理できます。

あなたの例では:

  • 注文(現在)
  • ORDER_HISTORY(HISTORY)

それは論理を簡単にするでしょう。

1
Jon Raynor

あなたの同僚は正しいです。主キーで並べ替えます。主キーはnotで、意味はありません。テーブルの各行を識別します。これは数値であり、レコードが作成された順序を意味します。

それはビジネスドメインの用語に完全に適合しませんが、イデオロギー上の理由から単純で明白なソリューションを見落とさないでください。特に、このソリューションでSQLクエリのソート句しか必要ない場合はなおさらです。

1
Greg Burghardt