我正在构建一个搜索评论的搜索界面。当用户点击搜索结果(评论)时,我想显示周围的评论。
我的模特:
Group (id, title) - A Group has many comments
Comment (id, group_id, content)
例如:
当用户点击comment.id
等于26的评论时,我会首先找到该论坛的所有评论:
comment = Comment.find(26)
comments = Comment.where(:group_id => comment.group_id)
我现在收到了该小组的所有评论。我当时想要做的是显示comment.id
26,之前最多10条评论,10条评论之后。
如何修改注释以显示偏移?
答案 0 :(得分:2)
听起来很简单,但要获得最佳性能真的很棘手。无论如何,必须让数据库完成工作。这比在客户端获取所有行和过滤/排序要快一个数量级。
如果“之前”和“之后”表示更小/更大comment.id
,我们进一步假设ID空间可能存在空白,此 一个 < / strong>查询应该全部执行:
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
的这两个索引组合应该非常快:
(id)
上的一个 - 可能会自动覆盖主键。(group_id, id)
对于只读数据,您可以创建一个具有无间隙行数的物化视图,这样可以使其更快。
More explanation about parenthesis, indexes, and performance in this closely related answer.
答案 1 :(得分: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)