13

しばらくの間、私は SQL で階層を処理する最善の方法と格闘してきました。隣接リストの制限と MPTT/ネストされたセットの複雑さに不満を感じた私は、単純なnode_key/node_key/...文字列として代わりにキー パスを単純に保存することを考え始めました。3 つの手法の長所と短所をまとめることにしました。

ノードの作成/削除/移動に必要な呼び出しの数:

  • 隣接性 = 1
  • MPTT = 3
  • パス = 1 (そのパスを含むすべてのノードで、古いノード パスを新しいノード パスに置き換えます)

ツリーを取得するために必要な呼び出しの数:

  • 隣接性 = [サブレベルの数]
  • MPTT = 1
  • パス = 1

ノード/祖先へのパスを取得するために必要な呼び出しの数:

  • 隣接性 = [スーパーレベルの数]
  • MPTT = 1
  • パス = 0

サブノードの数を取得するために必要な呼び出しの数:

  • 隣接性 = [サブレベルの数]
  • MPTT = 0 (左右の値から算出可能)
  • パス = 1

ノードの深さを取得するために必要な呼び出しの数:

  • 隣接性 = [スーパーレベルの数]
  • MPTT = 1
  • パス = 0

必須の DB フィールド:

  • 隣接性 = 1 (親)
  • MPTT = 3 (親、右、左)
  • パス = 1 (パス)

結論

ストアド パス手法は、1 つを除くすべてのユース ケースで、他の手法と同じか、または少ない呼び出しを使用します。この分析によると、パスの保存は明らかに勝者です。言うまでもなく、実装がはるかに簡単で、人間が読めるなどです.

問題は、保存されたパスは MPTT よりも強力な手法と見なされるべきではないということです。保存されたパスがより一般的に使用される手法ではないのはなぜですか? また、特定のインスタンスで MPTT を介して保存されたパスを使用しないのはなぜですか?

また、この分析が不完全だと思われる場合は、お知らせください。

アップデート:

保存されたパス ソリューションではできなくても、MPTT ですぐに実行できることが少なくとも 2 つあります。

  1. 追加のクエリなしで、各ノードのサブノード数を計算できます (上記)。
  2. 特定のレベルでノードに順序を課します。他のソリューションは順不同です。
4

2 に答える 2

10

また、フラットテーブルをツリーに解析するための最も効率的でエレガントな方法は何ですか?に対する私の回答で説明しているクロージャーテーブルの設計を検討することもできます。

ノードの作成/削除/移動に必要な呼び出し:

  • 閉鎖=1

ツリーを取得するために必要な呼び出し:

  • 閉鎖=1

ノード/祖先へのパスを取得するために必要な呼び出し:

  • 閉鎖=1

サブノードの数を取得するために必要な呼び出し:

  • 閉鎖=1

ノードの深さを取得するために必要な呼び出し:

  • 閉鎖=1

必要なDBフィールド:

  • Adjancency=1つ以上のフィールド/行
  • パス=1つ以上のフィールド/行
  • MPTT=2つまたは3つ以上のフィールド/行
  • クロージャー=追加のテーブルの2つまたは3つのフィールド。このテーブルには、最悪の場合はO(n ^ 2)行がありますが、ほとんどの実際の場合よりもはるかに少なくなっています。

他にもいくつか考慮事項があります。

無制限の深さをサポート:

  • 隣接=はい
  • MPTT=はい
  • パス=いいえ
  • 閉鎖=はい

参照整合性をサポートします。

  • 隣接=はい
  • MPTT=いいえ
  • パス=いいえ
  • 閉鎖=はい

また、プレゼンテーション「 SQLとPHPを使用した階層データのモデル」、および私の著書「SQLアンチパターン:データベースプログラミングの落とし穴の回避」でクロージャテーブルについても説明します。

于 2011-11-19T19:18:07.800 に答える
3

あなたの結論に問題があるのは、それが木を扱うことに関係する問題のほとんどを無視しているということです。

手法の有効性を「呼び出し回数」に減らすことで、十分に理解されたデータ構造とアルゴリズムが解決しようとするすべての問題を効果的に無視できます。つまり、最速の実行と低メモリおよびリソースのフットプリントです。

SQLサーバーへの「呼び出し回数」は、使用するのに適したメトリックのように見えるかもしれませんが(「コードが少ないように見える」)、結果が決して終了しない、実行が遅い、または多くのスペースを占めるプログラムである場合は、実際には役に立たないメトリック。

すべてのノードでパスを保存することにより、ツリーデータ構造を作成する必要はありません。代わりに、リストを作成しています。ツリーが最適化するように設計されている操作はすべて失われます。

これは小さな日付セットでは見づらいかもしれません(そして多くの場合、小さな木のリストの方が良いです)、サイズ500、1000、10kのデータセットでいくつかの例を試してください-パス全体を保存しない理由がすぐにわかります良い考えです。

于 2011-11-19T19:18:23.367 に答える