6

私は、より大きなシステムの基盤として使用されるグループ階層のデータベース設計に取り組んでいます。各グループには、他のグループと、リーフ オブジェクトとして「デバイス」を含めることができます (デバイスの下には何もありません)。

使用されているデータベースは MS SQL 2005 です。

グループにはさまざまな種類があり、これらは動的であり、ユーザーが実行時に定義できる必要があります。たとえば、グループ タイプは「顧客」、「アカウント」、「都市」、または「建物」、「フロア」であり、各タイプには、ユーザーが定義できる異なる属性セットがあります。ビジネス ルールも適用されます。たとえば、「フロア」は「ビルディング」グループの下にのみ含めることができ、これらは実行時に定義できます。

アプリケーション機能の多くは、これらのグループに基づいてレポートを実行することで得られるため、特定のグループ (およびすべてのサブグループ) に含まれるすべてのデバイスのリストを比較的高速に取得する方法が必要です。

変更された事前注文ツリー トラバーサル手法を使用してグループを格納することには、高速であるという利点がありますが、かなり複雑で壊れやすいという欠点があります。外部ユーザー/アプリケーションがデータベースを変更すると、完全に破損する可能性があります。また、ORM レイヤーも実装していますが、この方法では、ほとんどの ORM ライブラリでリレーションを使用するのが複雑になるようです。

共通のテーブル式と「標準の」id/parentid グループの関係を使用することは、複数の再帰クエリの実行を回避するための強力な方法のようです。この方法に欠点はありますか?

属性に関する限り、それらを保存する最良の方法は何ですか? グループに関連する細長いテーブル? 「名前」などの一般的な属性は、属性テーブルではなく、グループ テーブルに格納する必要がありますか (多くの場合、表示に必要なのは名前だけです)。

この方法を使用すると、パフォーマンスの問題が発生しますか (クアッドコア Xeon 2 Ghz、4GB RAM などの適切なハードウェア上で、それぞれ平均 6 つの属性を持つ平均 2000 のグループと、平均 10 人の同時ユーザーを想定します)。 、他のプロセスを割り引いて)?

ここで概説したものとはまったく異なるスキーマを自由に提案してください。気になる問題点をまとめてみました。

4

4 に答える 4

3

最も保守しやすい方法 (「標準」の親子セットアップ) を実際に構築し、少なくともいくつかの基本的なベンチマークを実行することをお勧めします。

特にデータセットがメモリに収まる場合は、適切なインデックスを使用してデータベース エンジンが実行できることに驚かれることでしょう。

グループごとに 6 つの属性、2000 個のグループ、および 30 バイト/属性を想定すると、360KB*期待される項目/グループ、つまり 400KB になります。1000 個の項目/グループがあると予想される場合、400MB のデータしか表示されません。これは問題なくメモリに収まり、すべてのデータがメモリ内にある場合、データベースは結合が高速です。

于 2008-09-22T02:26:12.963 に答える
2

共通テーブル式を使用すると、親子関係を持つグループのリストを取得できます。 別のアプリケーションで CTE を使用するsprocの例を次に示します。これはかなり効率的ですが、次の注意事項に注意してください。

  1. パーツが階層内で複数回発生する場合、各場所でレポートされます。結果の後処理が必要になる場合があります。
  2. CTE はいくぶん鈍感であり、クエリ内で結果をフィルター処理する範囲が限られています。CTE は、select ステートメント内で複数回表示されることはありません。

Oracle の CONNECT BY は、CTE ほど多くの制限をクエリ構造に課していないため、多少柔軟性がありますが、SQL Server を使用している場合、これはオプションではありません。

中間結果を巧妙に処理する必要がある場合は、CTE を使用して生のクエリを一時テーブルに取得し、そこから処理する sproc を記述します。SELECT INTO は、これで発生するトラフィックを最小限に抑えます。結果のテーブルはキャッシュに保存されるため、そのテーブルに対する操作はかなり高速になります。

役立つ可能性のあるいくつかの物理的な最適化:

  • 親のクラスター化されたインデックスにより、親の子ノードを取得する際の I/O の使用量が少なくなります。
  • メインの BOM テーブルをコアにキャッシュできるように、大量の RAM と (BOM テーブルのサイズに応じて) さらに多くの RAM を備えた 64 ビット サーバー。32 ビット O/S では、/3G ブート スイッチはあなたの味方であり、データベース サーバーにとって実際の欠点はありません。
  • DBCC PINTABLE は、データベース マネージャーが強制的にテーブルをキャッシュに保持するのに役立ちます。

Parent-Attribute Type-Attribute コーディング テーブルは、属性テーブルを含めると行数の組み合わせが爆発的に増加するため、CTE とうまく連携しません。これにより、属性でフィルタリングされたクエリ内のビジネス ロジックが除外されます。属性を BOM テーブル エントリに直接格納する方がはるかに優れています。

于 2008-09-22T12:10:37.227 に答える
1

変更された予約注文は、本質的に、Joe Celko の Nested Sets メソッドです。彼の著書「Trees and Hierarchies...」では、隣接リストと NS の両方を取り上げ、それぞれの長所と短所について説明しています。適切なインデックス作成により、隣接リストの CTE は最もバランスの取れたパフォーマンスを実現します。主に読み取りを行う場合は、NS の方が高速です。

あなたが説明しているように見えるのは、部品表プロセッサです。M$ ではありませんが、Graeme Birchall は無料の DB2 ブックを持っており、CTE を使用した階層処理に関する章があります (構文は、IIRC と実質的に同じであり、ANSI 構文が DB2 を採用し、M$ が採用されました): http://mysite .verizon.net/Graeme_Birchall/cookbook/DB2V95CK.PDF

于 2008-09-22T17:05:08.967 に答える
1

Tree Traversal の事前注文は非常に便利です。トラバーサル数をトリガーで最新の状態に保つことで、堅牢にすることができます。

私が使用した同様の手法は、すべての祖先と子孫をリストする (ancestor_id, descendant_id) の別のテーブルを保持することです。これは、事前注文のトラバーサル数とほぼ同じです。

別のテーブルを使用すると便利です。追加の結合が導入されても、複雑さが別のテーブルに取り除かれるためです。

于 2008-09-22T13:10:55.520 に答える