【问题标题】:How to get records based on an offset around a particular record?如何根据特定记录周围的偏移量获取记录?
【发布时间】:2013-01-08 21:59:31
【问题描述】:

我正在构建一个用于搜索 cmets 的搜索 UI。当用户点击搜索结果(评论)时,我想显示周围的 cmets。

我的模特:

Group (id, title) - A Group has many comments
Comment (id, group_id, content)

例如:

当用户点击 comment.id 等于 26 的评论时。我会首先找到该组的所有 cmets:

comment = Comment.find(26)
comments = Comment.where(:group_id => comment.group_id)

我现在拥有该组的所有 cmets。然后我想做的是显示comment.id 26,之前最多10 cmets,之后最多10 cmets。

如何修改 cmets 以显示该偏移量?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 postgresql postgresql-9.1


    【解决方案1】:

    听起来很简单,但要为此获得最佳性能却很棘手。在任何情况下,您必须让数据库来完成这项工作。这将比在客户端获取所有行和过滤/排序快一个数量级。

    如果“之前”和“之后”是指更小/更大comment.id,我们进一步假设 id 空间中可能存在间隙,这 一个 查询应该做所有事情:

    WITH x AS (SELECT id, group_id FROM comment WHERE id = 26) -- enter value once
    (
    SELECT *
    FROM   x
    JOIN   comment c USING (group_id)
    WHERE  c.id > x.id
    ORDER  BY c.id
    LIMIT  10
    )
    UNION ALL
    (
    SELECT *
    FROM   x
    JOIN   comment c USING (group_id)
    WHERE  c.id < x.id
    ORDER  BY c.id DESC
    LIMIT  10
    )
    

    我将用 Ruby 语法解释一下,这不是我的专业领域。

    返回 10 个较早的 cmets 和 10 个较晚的 cmets。如果存在更少,则更少。在UNION ALL 查询的第二段中使用&lt;= 以包含所选评论本身。

    如果您需要对行进行排序,请在顶部添加另一个查询级别,使用 ORDER BY

    与表comment的这两个索引结合起来应该会非常快:

    • (id) 上的一个 - 可能会自动覆盖主键。
    • 一个在(group_id, id)

    对于只读数据,您可以创建一个具有无间隙行号的物化视图,这样可以加快速度。

    More explanation about parenthesis, indexes, and performance in this closely related answer.

    【讨论】:

      【解决方案2】:

      类似:

      comment = Comment.find(26)
      before_comments = Comment.
        where('created_at <= ?', comment.created_at).
        where('id != ?', comment.id).
        where(group_id: comment.group_id).
        order('created_at DESC').limit(10)
      after_comments = Comment.
        where('created_at >= ?', comment.created_at).
        where('id != ?', comment.id).
        where(group_id: comment.group_id).
        order('created_at DESC').limit(10)
      

      【讨论】:

      • 如何确保只获取正确 group_id 中的 cmets?
      • 我很好奇这是否可以通过一个查询而不是多个查询?
      • 您可能可以编写一个复杂的 SQL 查询来一次性完成上述所有操作,但它的可读性会受到影响。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-10
      • 2021-10-01
      • 2013-05-10
      相关资源
      最近更新 更多