4

データベースにテーブルがあり、ハイブリッド入れ子集合(MPTT)モデル(lftrght値を持つモデル)と隣接リストモデル(parent_id各ノードに格納)を使用してツリー構造を格納しています。

my_table (id, parent_id, lft, rght, alias)

この質問は、ツリーのMPTTの側面のいずれにも関連していませんが、誰かがそれを活用する方法について良いアイデアを持っている場合に備えて、私はそれを残すと思いました。

エイリアスのパスを特定のノードに変換したい。例:"users.admins.nickf"ルートにある「users」の子であるエイリアス「admins」を持つノードの子であるエイリアス「nickf」を持つノードを検索します。には一意のインデックスがあります(parent_id, alias)

まず、関数を記述して、その部分へのパスを分割し、データベースに1つずつクエリを実行することから始めました。

SELECT `id` FROM `my_table` WHERE `parent_id` IS NULL AND `alias` = 'users';-- 1
SELECT `id` FROM `my_table` WHERE `parent_id` = 1 AND `alias` = 'admins';   -- 8
SELECT `id` FROM `my_table` WHERE `parent_id` = 8 AND `alias` = 'nickf';    -- 37

しかし、その後、可変量のネストを使用して、単一のクエリでそれを実行できることに気付きました。

SELECT `id` FROM `my_table` WHERE `parent_id` = (
    SELECT `id` FROM `my_table` WHERE `parent_id` = (
        SELECT `id` FROM `my_table`
        WHERE `parent_id` IS NULL AND `alias` = 'users'
    ) AND `alias`  = 'admins'
) AND `alias` = 'nickf';

サブクエリの数はパスのステップ数に依存するため、サブクエリが多すぎるという問題が発生しますか?(そんなことがあったら)

このクエリを実行するためのより良い/よりスマートな方法はありますか?

4

2 に答える 2

3

これは機能しますか?

select r0.id 
  from my_table as r0 
  join my_table as r1 on(r0.parent_id = r1.id) 
  join my_table as r2 on(r1.parent_id = r2.id)
 where r0.alias='nickf'
   and r1.alias='admins'
   and r2.alias='users'
   and r2.parent_id is null

ネストされたサブクエリは実際には必要ないようです。

または私は間違っている、何かが欠けていますか?

于 2010-05-28T04:25:21.623 に答える
2

I wondered about this myself, and was looking for something that didn't get slower as you went deeper (meaning more levels in both options above.) The problem I have with "my version", is that it has to create every possible path before it narrows the result down to the one you're actually searching for... so I think lexu's version should outperform mine even for very large nesting because it's a simple join, but I'm hoping someone might see it and wish to expand on it further.

また、この方法は、ストアドプロシージャ、および/またはその「パス」部分のビュー(HAVING句なし)から確実に恩恵を受けます。おそらくそれらの場合、それはより良い解決策ですが、残念ながら、現時点ではSQLのパフォーマンスについて十分に理解していません。データ(パスの可能な組み合わせの数)が大きくなると、私の速度は遅くなると言えますが、ビューを見ると(結果がキャッシュされ、それを使用して絞り込むため)、高速に見えます(私が見つけた最大のデータセット合計370でしたが、ある時点で、テスト用にはるかに大きなセットを作成します。)

SELECT node.id, GROUP_CONCAT(parent.alias
                 ORDER BY parent.lft SEPARATOR '.') AS path_name
FROM my_table AS node, my_table AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rght
GROUP BY node.id HAVING path_name = 'users.admins.nickf'
于 2010-06-11T06:31:20.693 に答える