Для целей постраничной, мне нужно выполнить запрос , с LIMIT
и OFFSET
статей. Но я также нужен подсчет числа строк , которые будут возвращены этим запросом без LIMIT
и OFFSET
статей.
Я хочу бежать:
SELECT * FROM table WHERE /* whatever */ ORDER BY col1 LIMIT ? OFFSET ?
А также:
SELECT COUNT(*) FROM table WHERE /* whatever */
В то же время. Есть ли способ сделать это, особенно способ, позволяющий Postgres оптимизировать его, чтобы он работал быстрее, чем запускать оба по отдельности?
Ответы:
Да. С простой оконной функцией:
SELECT *, count(*) OVER() AS full_count FROM tbl WHERE /* whatever */ ORDER BY col1 OFFSET ? LIMIT ?
Имейте в виду, что стоимость будет значительно выше, чем без общего числа, но обычно все же дешевле, чем два отдельных запроса. 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
чтобы устранить неоднозначность происхождения пустой строки.Это по-прежнему выполняет базовый запрос только один раз. Но он увеличивает накладные расходы на запрос и платит, только если это меньше, чем повторение базового запроса для подсчета.
Если доступны индексы, поддерживающие окончательный порядок сортировки, может быть полезно включить
ORDER BY
в CTE (избыточно).источник
MATERIALIZED
по умолчанию, на него дважды ссылаются.)edit: этот ответ действителен при получении неотфильтрованной таблицы. Я позволю, если это может кому-то помочь, но может не совсем ответить на первоначальный вопрос.
Ответ Эрвина Брандштеттера идеален, если вам нужно точное значение. Однако для больших таблиц часто требуется только довольно хорошее приближение. Postgres дает вам именно это, и он будет намного быстрее, поскольку ему не нужно будет оценивать каждую строку:
SELECT * FROM ( SELECT * FROM tbl WHERE /* something */ ORDER BY /* something */ OFFSET ? LIMIT ? ) data RIGHT JOIN (SELECT reltuples FROM pg_class WHERE relname = 'tbl') pg_count(total_count) ON true;
На самом деле я совершенно не уверен, есть ли преимущество в использовании экстернализации
RIGHT JOIN
или как в стандартном запросе. Это заслуживает некоторого тестирования.SELECT t.*, pgc.reltuples AS total_count FROM tbl as t RIGHT JOIN pg_class pgc ON pgc.relname = 'tbl' WHERE /* something */ ORDER BY /* something */ OFFSET ? LIMIT ?
источник
WHERE
предложению в ваших запросах. Второй запрос логически неверен (извлекает по одной строке для каждой таблицы в БД) - и более затратный при исправлении.Плохая практика - вызывать два раза один и тот же запрос для Просто, чтобы получить общее количество строк результата восстановления. Это займет время выполнения и приведет к потере ресурсов сервера.
Лучше, вы можете использовать
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()
вернет количество строк в наборе результатов, возвращенном этим оператором.источник
Нет.
Возможно, есть небольшая выгода, которую вы теоретически можете получить, управляя ими по отдельности с достаточно сложным оборудованием под капотом. Но если вы хотите знать, сколько строк соответствует условию, вам придется подсчитать их, а не только ограниченное подмножество.
источник