什么是在postgres中存储和检索任意深度嵌套结构的有效方法?

时间:2012-01-06 01:54:16

标签: ruby-on-rails postgresql activerecord hierarchical-data

在我的ruby-on-rails应用程序中,我有嵌套的注释,可以嵌套任意长度。

我尝试了不同的存储方式:

使用自联接:

belongs_to :parent, :class_name => 'Comment', :foreign_key => 'parent_id'
has_many :children, :class_name => 'Comment', :foreign_key => "parent_id"

使用祖先宝石

但问题是,无论我使用什么,都会有一定数量的SQL语句。 (1声明获取所有根注释,然后为每个根的子节点添加1个语句,然后为所有子节点添加1个语句,等等)

有没有更有效的方法来实现这一目标?

Postgres 9.1,但希望向后兼容的解决方案是首选。

2 个答案:

答案 0 :(得分:3)

您可以坚持使用parent_id指针列并使用find_by_sqlWITH RECURSIVE查询,让数据库一次完成所有工作。像这样:

comments = Comment.find_by_sql(%Q{
    with recursive tree(id) as (
        select c.id, c.column1, ...
        from comments c
        where c.id in (#{roots.join(',')})
        union all
        select c.id, c.column1, ...
        from comments c
        join tree on c.parent_id = tree.id
    )
    select id, column1, ...
    from tree
})

其中roots将是一个Ruby数组,其中包含您感兴趣的根节点的id。这将为您提供感兴趣的子树中的所有节点作为Comment实例。我过去曾经使用过这样的查询,而且即使是浅树,WITH RECURSIVE的速度也是迭代技术的两倍,我猜想更深的树木会看到更好的速度。

您正在使用的parent_id结构对于大多数事物都非常方便,并且与ActiveRecord的工作方式相当吻合。此外,坚持使用当前的结构意味着您可以单独留下其余的应用程序。

WITH RECURSIVE可用于PostgreSQL 8.4及更高版本。

答案 1 :(得分:1)

看一下awesome_nested_set,我想你会喜欢它。

https://github.com/collectiveidea/awesome_nested_set