これらのテーブル設計のうち、パフォーマンスに優れているのはどれですか?


16

アカウントで収集するための1日のコストを追跡する何かを作成するように求められ、これをサポートするデータベーステーブルスキーマを見つけようとしています。

これが私が知っていることです

  • 会社は250万以上のアカウントを持っています
  • これらのうち、彼らは現在、1か月あたり平均20万人働いています(現在は低い人員配置レベルで変化します)
  • 追跡したい13の異なるコストタイプがあり、将来さらに追加する可能性があると警告しています。
  • コストを毎日追跡したい
  • コストは在庫全体に分割されません。それらは、1か月あたり働くアカウント数(200,000)に分割されるか、ユーザーがアカウント識別子を入力してアカウントのグループにコストを適用するか、単にコストを適用するアカウントを指定できます。

最初に考えたのは、正規化されたデータベースです。

アカウントID
日付
CostTypeId
量

これに関する私の問題は、数学をすることです。このテーブルはすぐに巨大になります。13のすべてのコストタイプが今月のすべての作業済みアカウントに適用されると仮定すると200k * 13 * N days in month、これは1か月あたり約7500〜8000万レコード、または1年あたり約10億レコードになります。

私の2番目の考えは、それを少し非正規化することでした

アカウントID
日付
総費用
CostType1
CostType2
CostType3
CostType4
CostType5
CostType6
CostType7
CostType8
CostType9
CostType10
CostType11
CostType12
CostType13

この方法はより非正規化されており、1か月あたり最大600万レコード(200k * N days in month)、または1年あたり約7,200 万レコードを作成できます。最初の方法よりもはるかに少ないですが、将来会社が新しいコストタイプを決定した場合は、別のデータベース列を追加する必要があります。

2つの方法のうち、どちらがお好みですか?どうして?これをより良く処理できると考えられる別の選択肢はありますか?

私は、要約レポートと詳細レポートの両方のパフォーマンスのレポートに最も興味があります。アカウントに費用を配分するジョブは、誰もいないときに夜間に実行されます。二次的な懸念は、データベースのサイズです。既存のデータベースはすでに約300 GBであり、ディスク上のスペースは約500 GBであると思います。

データベースはSQL Server 2005です


別のディスクを入手してください。ディスクは安価です。これについて議論するために、会議の費用に2TBを割り当てることができます。

回答:


9

年間10億件のレコードはそれほど多くありません。

パーティション分割(Costtypeごと)とアーカイブを使用すると、管理しやすくなります。

格納するデータ項目の数はまだ 200k * 13 * Nです。列として、ページごとの行が少なくなり、行よりも多くのスペースが必要になります。"CostType1"が固定長のデータ型ではないが、わずかな場合に得られる可能性があります。

彼らが言うように「キス」


3
@Rachel私は、これほど大きなデータセットでパーティションスキーマを実装することを絶対にお勧めします。毎月の作業とレポートに焦点を合わせている場合は、その考え方に合ったパーティションキーを選択するのが最善です。また、パーティションを適切に構成すれば、テーブルからデータをステージングテーブルに簡単に切り替えることができます。これにより、大量のデータのロードとローリングデータセットの削除が数時間ではなく数秒で完了します。
デビッド

6

あなたの設計は確かに夜間または昼間の違いを生むことができますが、この場合、必要に応じてインデックスをカバーするなど、インデックスにもっと焦点を合わせます。また、テーブルパーティションなど、非常に大きなテーブルを処理するためにSQL Serverが提供するツールのいくつかも見ていきます。

このように考えると、テーブルに800億のレコードがあり、適切なインデックスが付けられていても、特定の時点で実際に関心があるレコードはディスク上で物理的にグループ化されます。SQLサーバーでのデータの編成方法により、インデックス境界で分割されたデータは、必要なものを取得するためにテーブル全体を読み取る必要がないため、別のテーブルにも存在する場合があります。

テーブルのパーティション分割も選択すると、アクセス時間と挿入時間を改善できます。


4

ノーマライズします。銀行で顧客アカウントの収益性の原価計算を行い、毎月数百万の口座にコストセンターまたは総勘定元帳またはその他のさまざまな手法で割り当てた数百のドライバーを使用して、2億5000万行を超える個別のコストを生成しました。

たとえば、ATMのサービスの総コストは、相対的な使用量に基づいてATMを使用していたアカウントに分割されました。したがって、ATMのサービスに100万ドルを費やし、1度に5人の顧客だけが使用し、1人が5回使用した場合、1人の顧客は銀行に500万ドル、他の顧客は銀行に100万ドルの費用がかかります。他のドライバーはもっと複雑かもしれません。

最終的に、あなたはおそらくそれがまばらであることに気付くでしょう-特定のアカウントは特定のソース/ドライバーからコストを得ていません-そしていくつかのアカウントは何も得ていません。正規化モデルでは、これらの行は存在しません。非正規化モデルでは、空の列を含む行が存在します。また、スパース正規化モデルでは、特定の "バケット"内のNULL以外のすべての行をチェックするよりも、行の存在が一般に(CostTypeのインデックスをカバーして)チェックする方が速いため、パフォーマンスが向上するはずです。すべての金額列のインデックス-ご覧のとおり、非常に無駄が多くなります)。


スパース-これは、すべての違いを生む非常に良い点です。スパースの場合、正規化することでスペースを節約できます。そうでなければ、そうではありません。しかし、ディスクスペースは安価であるため、個人的には最大限の柔軟性(正規化)に投票しています。

3

パフォーマンス上の利点に関係なく、私は間違いなくオプション1に賛成します。私の意見では、オプション2はPaulに支払いを強要します。


2

オプション1を使用し、レポート速度が今後問題になる場合は、表2も追加し、何らかの自動化された夜間/オフピークプロセスでレポートデータベースにデータを追加します。

また、必要に応じて、毎日の表2構造をさらに毎週、毎月、四半期、毎年のロールアップにロールアップすることも検討できます。

しかし、私が言ったように、「生の」データを適切な(正規化された)形式で保存することも選択します。


0

あなたが言及したボリュームを考慮して、私は2番目のオプションを選びますが、TotalCostはありません。それはまだ正規化されていると言えます。


編集:別の方法として、要件とAccountIdのサイズに応じて、次のことも検討できます。

AccountDate
-----------
AccountId  
Date  
AcDtID (surrogate key)

Costs
-------
AcDtID
CostTypeId  
Amount  

この設計では、非正規化されたTotalCostを最初のテーブルに追加し、毎晩再計算して、最初のテーブルのみでいくつかのレポートを実行できます。


TotalCostレポートの大部分が要約されているため、私はそこにいます。13の異なる値を追加するよりも、単一の値を照会する方が速いと思いました。

おそらく、しかし、あなたは本当に推移的な依存関係を持ち込みます。それらのレコードは更新されますか?または単に書いてから読むだけですか?

新しいコストがその日付範囲に適用されるたびに、レコードが更新されます。約1か月後、総費用が更新される可能性は低くなりますが、年間のサポート料金などが原因で引き続き可能です。

その後、各更新には2つの更新が必要になり、TotalCostフィールドには不整合のリスクが追加されます。

推移的な依存関係ですが、必ずしも矛盾のリスクではありません。CHECK()制約は、TotalCostが常にコストの合計であることを保証できます。
マイクシェリル 'キャットリコール'

0

実際にfirsテーブルを2つのテーブルに分割して、サブクエリを使用し、2番目の行を列または複数の列として選択できるようにする必要があります。その方が柔軟性が高いため、2番目のような結果をより簡単に得ることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.