Ответ 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 (избыточно).