私と数人の同僚が次のケースについて話し合っています。
OrderStatus
テーブルでは、_"Pending"
_、_"Available"
_、_"Returned"
_など、注文が時間内に通過するすべてのステータスを追跡しています。タイムスタンプフィールドがあります各ステータスがいつ追加されたかを追跡するために、表にあります。ただし、正確に同時に追加できるステータスが2つあり、その場合、両方のタイムスタンプがまったく同じ(ミリ秒を含む)になる場合があります。コードの別の部分では、注文が設定された最後のステータスを確認する必要があります。タイムスタンプで注文しているため、データベースから間違ったレコードを簡単に取得できます。
テーブルにはIDENTITY(1,1)
主キーがあり、同僚はその列を使用して注文する必要があると考えています。これにより、常にテーブルに追加された最新のレコードが必ず得られるからです。
IDENTITY
列には何の意味もないので、並べ替えには使用しないでください。タイムスタンプが確実に異なるようにThread.Sleep(1)
を実行して、そのフィールドを使用してソートします。
この場合のベストプラクティスは何だと思いますか?
数値が大きいほど高い状態を表すステータス値を使用します。それを降順でインデックスに追加します。次に、タイムスタンプ順の結果をプルバックしますandステータスを降順で返します。このようにして、最も遠い進行のエントリが常に返されます。
イベントソーシングアプローチが役立つと思います
http://martinfowler.com/eaaDev/EventSourcing.html
基本的に、オブジェクトを更新するたびに、オブジェクトをロードし、イベントを履歴に追加して、すべてを保存します。
オブジェクトを保存するとき、その間に履歴が更新されていないことを確認します。持っている場合は、新しい履歴からオブジェクトを再構築し、イベントの追加を再試行します
または、オブジェクトをロックして、他のイベントが終了するまで待機させることもできます。
これは、イベントが順序で保存されるだけでなく、順序どおりに処理されることを保証するため、auto-inc列などよりも優れています。
しかし、あなたの特定のケースでは、あなたのステータスは発生したイベントの関数であるように私には思えます。最後のイベントからステータスを読み取らせる代わりに、発生したすべてのイベントに基づいて計算を行います。
この場合、どちらのイベントが最初に発生したか、または2つが同時に発生したかは問題ではありません。
すなわち
「注文が選択されました」と「顧客の信用調査に合格した」と言います
概念的には、これらの両方が同時に発生する可能性がありますが、ステータスは
「未選択」-未選択のイベント
「保留中の信用調査」-選択されたイベントが信用調査イベントなし
「配達準備完了」-選択され、かつ信用調査済み
より良い方法は、2つのテーブルを最新のものと履歴として保持することです。現在のテーブルは常に最新の更新になります。もう1つのテーブルは、常に挿入と読み取りだけの履歴テーブルです。最新のレコードを取得する場合は、現在のテーブルをクエリします。ダーティリードを許可しない場合は、常に最新のレコードになります。履歴が必要な場合は、履歴テーブルをクエリし、PKで並べ替えます。
現在のテーブルでは、タイムスタンプを保持したいので、誰かが読み取り後にレコードを更新した場合、更新を行う前に競合を適切に処理できます。履歴テーブルでは常に挿入しているため、チェックは必要ありません。必要に応じて、現在のテーブルからトリガーを使用して履歴の挿入を処理できます。
あなたの例では:
それは論理を簡単にするでしょう。
あなたの同僚は正しいです。主キーで並べ替えます。主キーはnotで、意味はありません。テーブルの各行を識別します。これは数値であり、レコードが作成された順序を意味します。
それはビジネスドメインの用語に完全に適合しませんが、イデオロギー上の理由から単純で明白なソリューションを見落とさないでください。特に、このソリューションでSQLクエリのソート句しか必要ない場合はなおさらです。