Разбиение на страницы: выяснить, на какой странице находится элемент (заданный первичный ключ и порядок сортировки) - PullRequest
6 голосов
/ 06 июня 2011

Допустим, я делаю нумерацию страниц следующим образом:

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) .

Мой вопрос: что такое самый эффективный способ выяснить, на какой странице находится статья, если я

а) знаю идентификатор_сталии

б) знаю, сортировка выполняется по ORDER BY article_rating?

Это должно быть эффективно, потому что я собираюсь делать этот тип запросов очень часто.

Было бы еще лучше, если бы он не только выплевывал номер страницы, но и все статьи на этой странице.

Так, например, если все статьи отсортированы по рейтингу и каждые десять из них помещены на другую страницу, я хочу выяснить, на какой странице находится статья с идентификатором 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 Ответ

2 голосов
/ 06 июня 2011

РЕДАКТИРОВАТЬ См. Второй запрос ниже, он намного лучше, чем этот первый.

Предполагая, что Postgres 9.0 или лучше, вы должны использовать оконную функцию, чтобы получить row_number накаждый предмет.Затем вы делите row_number конкретной статьи на items_per_page (и округление), чтобы получить номер страницы.Единственное доступное улучшение эффективности - это, по крайней мере, не запрашивать статьи, которые приходят после рассматриваемой.Таким образом, вы получите что-то вроде этого:

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')

Обычно нам не нравятся предложения OR в предложениях WHERE, потому что они могут снизить производительность, но это должно быть довольно безопасно, потому что каждое предложение должнобыть оптимизируемым, если проиндексирован article_rating.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...