Ja. Med en enkel fönsterfunktion:
SELECT *, count(*) OVER() AS full_count
FROM tbl
WHERE /* whatever */
ORDER BY col1
OFFSET ?
LIMIT ?
Tänk på att kostnaden kommer att vara betydligt högre än utan det totala antalet, men vanligtvis fortfarande billigare än två separata frågor. Postgres måste faktiskt räkna alla rader i båda fallen, vilket medför en kostnad beroende på det totala antalet kvalificerade rader. Detaljer:
- Bästa sättet att få resultaträkningen innan LIMIT tillämpades
Men , som Dani påpekade, när OFFSET
är minst lika stort som antalet rader som returneras från basfrågan, returneras inga rader. Så vi får inte heller full_count
.
Om det inte är acceptabelt, en möjlig lösning för att alltid returnera hela antalet skulle vara med en CTE och en 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;
Du får en rad med NULL-värden med full_count
läggs till om OFFSET
är för stor. Annars läggs den till på varje rad som i den första frågan.
Om en rad med alla NULL-värden är ett möjligt giltigt resultat måste du kontrollera offset >= full_count
för att disambiguera ursprunget för den tomma raden.
Detta kör fortfarande basfrågan bara en gång. Men det lägger till mer overhead till frågan och betalar bara om det är mindre än att upprepa basfrågan för räkningen.
Om index som stöder den slutliga sorteringsordningen är tillgängliga kan det löna sig att inkludera ORDER BY
i CTE (redundant).