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

uni*_*nop 6 sql postgresql pagination

假设我像这样做分页:

SELECT article_id, 
       article_content 
FROM articles 
ORDER BY article_rating 
OFFSET (page - 1) * items_per_page 
LIMIT items_per_page;
Run Code Online (Sandbox Code Playgroud)

我有一个索引(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;
Run Code Online (Sandbox Code Playgroud)

Ken*_*wns 3

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

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

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'
Run Code Online (Sandbox Code Playgroud)

编辑回答评论中的问题。是的,我刚刚意识到有一种更好的方法可以做到这一点。通过运行 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')
Run Code Online (Sandbox Code Playgroud)

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