Ja. Mit einer einfachen Fensterfunktion:
SELECT *, count(*) OVER() AS full_count
FROM tbl
WHERE /* whatever */
ORDER BY col1
OFFSET ?
LIMIT ?
Beachten Sie, dass die Kosten wesentlich höher sind als ohne die Gesamtzahl, aber in der Regel immer noch billiger als zwei separate Abfragen. Postgres muss tatsächlich alle Zeilen zählen so oder so, was Kosten verursacht, die von der Gesamtzahl der qualifizierten Zeilen abhängen. Einzelheiten:
- Bester Weg, um die Ergebnisanzahl zu erhalten, bevor LIMIT angewendet wurde
Allerdings , wie Dani betonte, wenn OFFSET
mindestens so groß ist wie die Anzahl der von der Basisabfrage zurückgegebenen Zeilen, werden keine Zeilen zurückgegeben. Wir bekommen also auch nicht full_count
.
Wenn dies nicht akzeptabel ist, eine mögliche Umgehung, um immer die vollständige Anzahl zurückzugeben wäre mit einem CTE und einem 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;
Mit full_count
erhalten Sie eine Zeile mit NULL-Werten angehängt wenn OFFSET
ist zu groß. Andernfalls wird es wie in der ersten Abfrage an jede Zeile angehängt.
Wenn eine Zeile mit allen NULL-Werten ein mögliches gültiges Ergebnis ist, müssen Sie offset >= full_count
überprüfen um den Ursprung der leeren Zeile eindeutig zu machen.
Dadurch wird die Basisabfrage immer noch nur einmal ausgeführt. Aber es fügt der Abfrage mehr Overhead hinzu und zahlt sich nur aus, wenn das weniger ist als die Wiederholung der Basisabfrage für die Zählung.
Wenn Indizes verfügbar sind, die die endgültige Sortierreihenfolge unterstützen, kann es sich lohnen, den ORDER BY
aufzunehmen im CTE (redundant).