0

I'm building a search UI which searches for comments. When a user clicks on a search result (comment), I want to show the surrounding comments.

My model:

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

For example:

When a user clicks on a comment with comment.id equal to 26. I would first find all the comments for that group:

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

I now have all of the group's comments. What I then want to do is show comment.id 26, with a max of 10 comments before and 10 comments after.

How can I modify comments to show that offset?

4

2 回答 2

2

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

如果“之前”和“之后”的意思是更小/更大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 条之前的评论和 10 条之后的评论。如果存在更少,则更少。<=在查询的第二条腿中使用以UNION ALL包含所选评论本身。

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

结合表的这两个索引应该非常快comment

  • one on (id)- 可能会自动覆盖主键。
  • 一上(group_id, id)

对于只读数据,您可以创建一个具有无间隙行号的物化视图,这将使其更快。

在这个密切相关的答案中,更多关于括号、索引和性能的解释。

于 2013-01-09T01:48:06.267 回答
0

就像是:

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)
于 2013-01-08T22:15:28.263 回答