PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Führen Sie eine Abfrage mit einem LIMIT/OFFSET aus und erhalten Sie auch die Gesamtzahl der Zeilen

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).