Ja. Met een eenvoudige vensterfunctie:
SELECT *, count(*) OVER() AS full_count
FROM tbl
WHERE /* whatever */
ORDER BY col1
OFFSET ?
LIMIT ?
Houd er rekening mee dat de kosten aanzienlijk hoger zullen zijn dan zonder het totale aantal, maar doorgaans nog steeds goedkoper dan twee afzonderlijke zoekopdrachten. Postgres moet daadwerkelijk alle rijen tellen hoe dan ook, wat kosten met zich meebrengt, afhankelijk van het totale aantal kwalificerende rijen. Details:
- De beste manier om het aantal resultaten te krijgen voordat LIMIT werd toegepast
Echter , zoals Dani opmerkte, toen OFFSET
minstens zo groot is als het aantal rijen dat wordt geretourneerd door de basisquery, worden er geen rijen geretourneerd. We krijgen dus ook geen full_count
.
Als dat niet acceptabel is, een mogelijke oplossing om altijd het volledige aantal terug te geven zou zijn met een CTE en een 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;
U krijgt één rij met NULL-waarden met de full_count
toegevoegd als OFFSET
is te groot. Anders wordt het aan elke rij toegevoegd, zoals in de eerste zoekopdracht.
Als een rij met alle NULL-waarden een mogelijk geldig resultaat is, moet u offset >= full_count
aanvinken om de oorsprong van de lege rij ondubbelzinnig te maken.
Hierdoor wordt de basisquery nog steeds maar één keer uitgevoerd. Maar het voegt meer overhead toe aan de zoekopdracht en loont alleen als dat minder is dan het herhalen van de basisquery voor de telling.
Als er indexen beschikbaar zijn die de uiteindelijke sorteervolgorde ondersteunen, kan het lonen om de ORDER BY
. op te nemen in de CTE (overbodig).