4

我的数据库中有一个表,我使用混合嵌套集 (MPTT) 模型(具有lftrght值的模型)和邻接列表模型(存储parent_id在每个节点上)存储树结构。

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

这个问题与树的任何 MPTT 方面都没有关系,但我想我会留下它,以防万一有人知道如何利用它。

我想将别名路径转换为特定节点。例如:"users.admins.nickf"将找到别名为“nickf”的节点,该节点是别名为“admins”的节点的子节点,别名“admins”是位于根目录的“users”的子节点。上有一个唯一索引(parent_id, alias)

我从编写函数开始,以便将路径拆分为各个部分,然后一一查询数据库:

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

我自己也想知道这一点,并且正在寻找随着您深入而不会变慢的东西(这意味着上面两个选项中的更多级别。)我对“我的版本”的问题是它必须创建每条可能的路径在将结果缩小到您实际搜索的结果之前......所以我认为 lexu 的版本即使对于非常大的嵌套也应该优于我的版本,因为它是一个简单的连接,但我希望有人会看到它并希望扩展进一步。

此外,这样做肯定会受益于存储过程和/或它的“路径”部分的视图(没有 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 回答