分页:找出项目所在的页面(给定主键和排序顺序)

时间:2011-06-06 13:56:29

标签: sql postgresql pagination

让我说我像这样做分页:

SELECT article_id, 
       article_content 
FROM articles 
ORDER BY article_rating 
OFFSET (page - 1) * items_per_page 
LIMIT items_per_page;

我的索引超过(article_rating,article_id)

我的问题是:如果我

最有效的方式是什么方式可以找出文章在哪个页面上?

a)知道article_id

b)知道排序是ORDER BY article_rating?

它需要高效,因为我会经常这样做。

如果它不仅吐出页码,而且还吐出该页面上的所有文章,那就更好了。

因此,例如,如果所有文章按其评级排序,并且每十个文章都放在不同的页面上,我想弄清楚ID为839的文章在哪个页面上。

我正在使用PostgreSQL 8.4(如果需要,我愿意更新。)

谢谢!

修改

正如下面的评论所指出的,我的查询应该如下所示:

SELECT article_id, 
       article_content 
FROM articles 
ORDER BY article_rating,
         article_id
OFFSET (page - 1) * items_per_page 
LIMIT items_per_page;

1 个答案:

答案 0 :(得分:2)

编辑请参阅下面的第二个查询,它比第一个查询要好得多。

假设Postgres 9.0或更高版本,您必须使用窗口函数来获取每个项目的row_number。然后用items_per_page(和round)划分特定文章的row_number以获取页码。唯一可用的效率改进是至少不查询之后的文章。所以你得到这样的东西:

Select ceiling(rowNumber/items_per_page)
  from (
SELECT article_id
     , article_content 
     , row_number() over (order by article_rating, article_id)
       as rowNumber
  FROM articles 
 where article_rating <= (select article_rating
                            from articles
                           where article_id = 'xxxx' )
 ORDER BY article_rating,
          article_id
       ) x
 where article_id = 'xxxx'

编辑回复评论中的问题。是的,我刚刚意识到有一个更好的方法来做到这一点。通过运行count(*)而不是遍历索引。

Select ceiling(count(*)/items_per_page)
  FROM articles 
 where article_rating < (select article_rating
                           from articles
                          where article_id = 'xxxx' )
    or ( article_rating = (select article_rating
                           from articles
                          where article_id = 'xxxx' )
        and article_id <= 'xxxx')

通常我们不喜欢WHERE子句中的OR子句,因为它们会降低性能,但是这个应该非常安全,因为如果article_rating被索引,每个子句都应该是可优化的。