フラグとテーブルの分割


10

私は(潜在的に)数千万のレコードを含むアイテムのテーブルを設計しています。一部のアイテムは、管理者によって「承認」されるまで使用できません。「使用」とは、そのような項目が「承認」されるまで他のテーブルで参照されないことを意味します。アイテムの最大50%は、いつでも「承認されない」可能性があります。レコードは「承認」される可能性がありますが、その逆はできません。

2つの設計オプションを検討します。

  • ビットフラグ
  • 「未承認」アイテムの個別のテーブル-アイテムが承認されると、「通常」テーブルに移動されます(アイテムのIDの更新は問題ではありません)

2番目のオプションの方がはるかに良いと思います。ビットフラグは行ごとに1バイトしかとらないため、問題はありません。ただし、同じテーブルに100万件の承認済みレコードと100万件の未承認レコードがある場合、承認済みレコードを使用した操作のスキャン時間は増加します。

質問は、代わりに最初の(ビットフラグ)オプションを検討する必要がありますか?説明されている状況で何かメリットがありますか?


1
フィルターされたインデックスを使用して、承認済みレコードへのアクセスを高速化できることを覚えておくと役立ちます。brentozar.com/archive/2013/11/...
mendosi

残念ながら、フィルター処理されたインデックスは、パラメーター化されたクエリでは使用されません。
Dima

@Dimaそれは完全に真実ではありません。フィルターされたインデックスにsayがWHERE status='A'あり、クエリにがWHERE status = 'A' AND (... other columns and parameters here...)ある場合、インデックスは引き続き使用される可能性があります。
ypercubeᵀᴹ

回答:


6

分割ビューを使用すると、両方の方法でそれを実現できます

相互に排他的な値を使用して、制約によって強制される各ステータスの基礎となるテーブルを作成します。次に、基になるテーブルをUNIONで結合するビュー。ビューまたは各ベーステーブルは明示的に参照できます。ビューを通じて行のステータスが更新されると、DBMSは1つのベーステーブルから行を削除し、新しいステータスに対応する行に挿入します。各ベーステーブルには、その使用パターンに応じて個別にインデックスを付けることができます。オプティマイザは、可能であれば、インデックス参照を単一の対応するベーステーブルに解決します。

利点は
、a)より浅いインデックスです。ただし、インデックスのファンアウトで計算を行ってください。そのスケールでは、ステータス値間で分割され、インデックスは、結合されたテーブルと同じように、分割されたテーブルでも同じ深さになる可能性があります。
b)アプリケーションコードを変更する必要はありません。データは連続した全体として表示され続けます。
c)制約付きの新しいベーステーブルを追加し、ビューを再作成することで、将来の新しいステータス値を含めることができます。

コストはそのすべてのデータ移動です。ステータスの更新ごとに2つのページと関連するインデックスが書き込まれます。対処するIOが多い。そのような動きも断片化を引き起こします。


5

(潜在的に)数千万のレコードを含むアイテムのテーブル。

SQL Serverが効率的に処理できることを考えると、実際にはそれほど多くありません。もちろん、私は以前の仕事の1つを覚えています。最大のテーブル(単一インスタンスシステム)の1つに200万行があり、それが私がこれまで扱ってきた最大の数でした。次に、次のジョブには17の実稼働インスタンスがあり、いくつかのテーブルには数億行があり、それらすべてが10億を超える行を持つ複数のファクトテーブルを持つデータウェアハウスに集約されました。誤解しないでください。私は数千万の行をあざけるのではなく、優れたデータモデルと適切なインデックス付け(およびインデックスのメンテナンス)によって、SQL Serverが多くのことを処理できることを強調しています。

アイテムの最大50%は、いつでも「承認されない」可能性があります。

うーん。それは正しく聞こえません。「承認」エントリの割合は、新しいエントリを取得する割合の半分になりますか?2つの新しいエントリごとに、1つだけが「承認」されますか?200万行の例で、「承認済み」と「未承認」のそれぞれに100万行、数年後、さらに1000万のエントリがある場合、「承認済み」と「未承認」のそれぞれに600万行が予想されますか?それとも、100万件の「未承認」がある程度一定であり、1,000万件の新規エントリがあっても、1100万件が「承認」され、100万件が「未承認」になるのでしょうか。

レコードは「承認」される可能性がありますが、その逆はできません。

今日もそうですが、状況は時間とともに変化するため、企業が「非承認」、または「アーカイブ済み」などの他のステータスを許可することを常に決定する可能性があります。

だから、選択肢を見てみましょう:

フラグ(またはTINYINT「ステータス」)

  • 各ステータスのクエリでは少し遅い
  • 時間の経過に伴う柔軟性の向上/新しいルックアップステータス値のみを使用した3番目の状態(「アーカイブ済み」など)などの変更の組み込みが容易 新しいテーブルは(必要に応じて)なく、一部の新しいコード、一部のコードのみが更新されました。
  • 作業(コード、テストなど)が少なく、単一のTINYINT列の更新でエラーが発生する余地が少ない
  • それほど複雑ではない=長期にわたるメンテナンスコストの削減、新入社員が理解するためのトレーニング時間の短縮
  • (おそらく)1つのテーブルが更新されるため、トランザクションログへの影響が小さい
  • 2つのテーブル間の「RecordStatus」とFKのルックアップテーブルが必要です。

2つの個別のテーブル(1つは「承認済み」、もう1つは「未承認」)

  • 各ステータスのクエリでは少し高速
  • 時間の経過に伴う柔軟性の低下/ 3番目の状態(「アーカイブ済み」など)などの変更を組み込むのが難しくなる。新しい状態では、おそらく別のテーブルと、間違いなく新しく更新されたコードが必要です。
  • より多くの作業(つまり、コード、テストなど)および「未承認」テーブルから「承認済み」テーブルへのレコードの移動エラーの余地
  • より複雑=長期にわたるメンテナンスコストの増加、新入社員が理解するためのトレーニング時間が長くなる
  • (おそらく)1つのテーブルが削除され、1つが挿入されるため、トランザクションログへの影響が大きい
  • アイテムのIDの更新」について心配する必要はありません。未承認のテーブルには列であるID列があり、IDENTITY承認済みのテーブルにはない列がありますIDENTITY(そこでは必要ないため)。したがって、ID値は、レコードがテーブル間を移動しても一貫性を保ちます。

個人的には、StatusID最初は列のある単一のテーブルを使用します。2つのテーブルを使用すると、過度に複雑で時期尚早の最適化のように見えます。そのような最適化は、レコード数が数億にあり、インデックス作成によってパフォーマンスが向上しない場合に説明できます。


これは、動きの速いデータを含むテーブルです。多くの場合、多くの新しい行が入力され、多くの場合、行は削除されます。すべての詳細(ビジネス上の決定、クライアントのコーディングなど)を削除して、1つのトピックのみに集中しようとしました。基本的には、ビットフラグ付きの古いデザインのテーブルがあります。フラグが1に設定されている行は、他のテーブルでは決して使用されないことを100%知っています。そのため、そこでのみ発生し、別のテーブルに移動される可能性があると感じています。テーブルは、DBへのほとんどすべてのクエリでスキャンされます。したがって、その「重み」を減らすと、CPU / IO演算を減らすことができる可能性があります。
Dima、2016年

3
分割テーブルのもう1つの利点:「承認済み」テーブルのみを参照するFKを持つことができます。
ypercubeᵀᴹ

単一エンティティの分割テーブルに関するもう1つの問題は、制約の整合性です。他のテーブルからの参照は、レコードが動き回るとうまく機能しません。これには、分割テーブルのミラー参照テーブルなどのこれらの問題を回避するためにコードを記述する必要があります->非常に面倒
user1567453
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.