Запустите запрос с помощью LIMIT/OFFSET, а также получите общее количество строк

Для целей разбиения на страницы мне нужно выполнить запрос с предложениями LIMIT и OFFSET. Но мне также нужно количество строк, которое будет возвращено этим запросом без предложений LIMIT и OFFSET.

Я хочу запустить:

SELECT * FROM table WHERE /* whatever */ ORDER BY col1 LIMIT ? OFFSET ?

А также:

SELECT COUNT(*) FROM table WHERE /* whatever */

В то же время. Есть ли способ сделать это, в частности, способ, позволяющий Postgres оптимизировать его, чтобы он работал быстрее, чем работает как индивидуально?

Ответы

Ответ 1

Да. С простой функцией окна:

SELECT *, count(*) OVER() AS full_count
FROM   tbl
WHERE  /* whatever */
ORDER  BY col1
LIMIT  ?
OFFSET ?

Имейте в виду, что стоимость будет значительно выше, чем без общего количества, но все же дешевле, чем два отдельных запроса. Postgres должен фактически подсчитывать все строки в любом случае, что накладывает стоимость в зависимости от общего количества квалификационных строк. Детали:

Однако, как показала Дани, когда OFFSET по крайней мере так же велико, как количество строк, возвращаемых из базового запроса, строки не возвращаются. Таким образом, мы также не получаем full_count.

Если это неприемлемо, возможное обходное решение, которое всегда возвращает полный счет, будет с CTE и OUTER JOIN:

WITH cte AS (
   SELECT *
   FROM   tbl
   WHERE  /* whatever */
   )
SELECT *
FROM  (
   TABLE  cte
   ORDER  BY col1
   LIMIT  ?
   OFFSET ?
   ) sub
RIGHT  JOIN (SELECT count(*) FROM cte) c(full_count) ON true;

Вы получаете строку значений NULL при добавлении full_count если OFFSET слишком велико. Или он добавляется к каждой строке, как в первом запросе.

Если строка со всеми значениями NULL является допустимым результатом, вам необходимо проверить offset >= full_count чтобы устранить offset >= full_count возникновения пустой строки.

Это все еще выполняет базовый запрос только один раз. Но он добавляет дополнительные накладные расходы на запрос и платит только если это меньше, чем повторение базового запроса для счета.

Если индексы, поддерживающие окончательный порядок сортировки, доступны, он может заплатить за включение ORDER BY в CTE (избыточно).

Ответ 2

Это плохая практика - вызывать два раза один и тот же запрос для Just, чтобы получить общее количество строк возвращаемого результата. Это займет время выполнения и приведет к потере ресурсов сервера.

Более того, вы можете использовать SQL_CALC_FOUND_ROWS в запросе, который скажет MySQL выбрать общее количество строк вместе с результатами запроса лимита.

Пример установлен как:

SELECT SQL_CALC_FOUND_ROWS employeeName, phoneNumber FROM employee WHERE employeeName LIKE 'a%' LIMIT 10;

SELECT FOUND_ROWS();

В приведенном выше запросе просто добавьте опцию SQL_CALC_FOUND_ROWS в запросе на остальные запросы и выполните вторую строку, т.е. SELECT FOUND_ROWS() возвращает количество строк в наборе результатов, возвращаемых этим оператором.

Ответ 3

Нет.

Там, возможно, какой-то небольшой выигрыш, который вы могли бы теоретически получить, управляя ими индивидуально, с достаточно сложными машинами под капотом. Но, если вы хотите знать, сколько строк соответствует условию, вам придется рассчитывать их, а не просто LIMITed подмножество.