Para fines de paginación, necesito ejecutar una consulta con las cláusulas LIMIT
y OFFSET
. Pero también necesito un recuento de la cantidad de filas que devolvería esa consulta sin las cláusulas LIMIT
y OFFSET
.
Quiero correr:
SELECT * FROM table WHERE /* whatever */ ORDER BY col1 LIMIT ? OFFSET ?
Y:
SELECT COUNT(*) FROM table WHERE /* whatever */
Al mismo tiempo. ¿Hay alguna forma de hacerlo, en particular una forma que permita a Postgres optimizarlo, de modo que sea más rápido que ejecutar ambos individualmente?
Respuestas:
Si. Con una función de ventana simple:
SELECT *, count(*) OVER() AS full_count FROM tbl WHERE /* whatever */ ORDER BY col1 OFFSET ? LIMIT ?
Tenga en cuenta que el costo será sustancialmente más alto que sin el número total, pero generalmente más económico que dos consultas separadas. Postgres tiene que contar todas las filas de cualquier manera, lo que impone un costo que depende del número total de filas calificadas. Detalles:
Sin embargo , como señaló Dani , cuando
OFFSET
es al menos tan grande como el número de filas devueltas de la consulta base, no se devuelven filas. Entonces tampoco lo conseguimosfull_count
.Si eso no es aceptable, una posible solución para devolver siempre el recuento completo sería con un CTE y un
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;
Obtiene una fila de valores NULL con el
full_count
if adjuntoOFFSET
es demasiado grande. De lo contrario, se agrega a cada fila como en la primera consulta.Si una fila con todos los valores NULL es un posible resultado válido, debe verificar
offset >= full_count
para eliminar la ambigüedad del origen de la fila vacía.Esto aún ejecuta la consulta base solo una vez. Pero agrega más gastos generales a la consulta y solo paga si eso es menos que repetir la consulta base para el recuento.
Si los índices que soportan el orden de clasificación final están disponibles, podría ser útil incluirlos
ORDER BY
en el CTE (de forma redundante).fuente
MATERIALIZED
predeterminado, se hace referencia dos veces)editar: esta respuesta es válida al recuperar la tabla sin filtrar. Lo dejaré en caso de que pueda ayudar a alguien, pero es posible que no responda exactamente a la pregunta inicial.
La respuesta de Erwin Brandstetter es perfecta si necesita un valor exacto. Sin embargo, en tablas grandes a menudo solo se necesita una aproximación bastante buena. Postgres le brinda precisamente eso y será mucho más rápido ya que no necesitará evaluar cada fila:
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;
En realidad, no estoy seguro de si existe una ventaja para externalizar
RIGHT JOIN
o tenerlo como en una consulta estándar. Merecería algunas pruebas.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 ?
fuente
WHERE
cláusula de tus consultas. La segunda consulta es lógicamente incorrecta (recupera una fila por cada tabla en la base de datos) y es más cara cuando se corrige.Es una mala práctica llamar dos veces la misma consulta para Just para obtener el número total de filas del resultado de retorno. Tomará tiempo de ejecución y desperdiciará los recursos del servidor.
Mejor, puede usar
SQL_CALC_FOUND_ROWS
en la consulta que le dirá a MySQL que obtenga el número total de filas junto con los resultados de la consulta de límite.Ejemplo establecido como:
SELECT SQL_CALC_FOUND_ROWS employeeName, phoneNumber FROM employee WHERE employeeName LIKE 'a%' LIMIT 10; SELECT FOUND_ROWS();
En la consulta anterior, simplemente agregue la
SQL_CALC_FOUND_ROWS
opción en el resto de la consulta requerida y ejecute la segunda línea, es decir,SELECT FOUND_ROWS()
devuelve el número de filas en el conjunto de resultados devuelto por esa declaración.fuente
No.
Quizás haya una pequeña ganancia que teóricamente podría obtener al ejecutarlos individualmente con suficiente maquinaria complicada debajo del capó. Pero, si desea saber cuántas filas coinciden con una condición, tendrá que contarlas en lugar de solo un subconjunto LIMITADO.
fuente