Do celów paginacji potrzebuję uruchomić zapytanie z klauzulami LIMIT
i OFFSET
. Ale potrzebuję również liczby wierszy, które zostaną zwrócone przez to zapytanie bez klauzul LIMIT
i OFFSET
.
Chcę biec:
SELECT * FROM table WHERE /* whatever */ ORDER BY col1 LIMIT ? OFFSET ?
I:
SELECT COUNT(*) FROM table WHERE /* whatever */
W tym samym czasie. Czy istnieje sposób, aby to zrobić, w szczególności sposób, który pozwala Postgresowi zoptymalizować go, aby był szybszy niż uruchamianie obu indywidualnie?
Odpowiedzi:
Tak. Dzięki prostej funkcji okna:
SELECT *, count(*) OVER() AS full_count FROM tbl WHERE /* whatever */ ORDER BY col1 OFFSET ? LIMIT ?
Należy pamiętać, że koszt będzie znacznie wyższy niż bez całkowitej liczby, ale zazwyczaj nadal będzie tańszy niż dwa oddzielne zapytania. Postgres musi faktycznie policzyć wszystkie wiersze w obie strony, co narzuca koszt w zależności od całkowitej liczby kwalifikujących się wierszy. Detale:
Jednak , jak zauważył Dani , gdy
OFFSET
jest co najmniej tak duża, jak liczba wierszy zwróconych z zapytania podstawowego, żadne wiersze nie są zwracane. Więc my też nie dostajemyfull_count
.Jeśli to nie do zaakceptowania, możliwym obejściem, aby zawsze zwracać pełną liczbę, byłoby użycie CTE i
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;
Otrzymasz jeden wiersz wartości NULL z
full_count
dołączonym jeśliOFFSET
jest za duży. W przeciwnym razie jest dołączany do każdego wiersza, tak jak w pierwszym zapytaniu.Jeśli wiersz zawierający wszystkie wartości NULL jest możliwym prawidłowym wynikiem, należy sprawdzić,
offset >= full_count
aby ujednoznacznić pochodzenie pustego wiersza.To nadal wykonuje zapytanie podstawowe tylko raz. Ale dodaje więcej narzutu do zapytania i płaci tylko wtedy, gdy to mniej niż powtórzenie zapytania podstawowego dla liczby.
Jeśli dostępne są indeksy obsługujące ostateczny porządek sortowania, może się opłacić uwzględnienie
ORDER BY
w CTE (nadmiarowo).źródło
MATERIALIZED
domyślnie, przywoływany dwukrotnie.)edycja: ta odpowiedź jest poprawna podczas pobierania niefiltrowanej tabeli. Pozwolę na to na wypadek, gdyby mogło to komuś pomóc, ale może nie odpowiedzieć dokładnie na początkowe pytanie.
Odpowiedź Erwina Brandstettera jest idealna, jeśli potrzebujesz dokładnej wartości. Jednak na dużych stołach często potrzebujesz tylko całkiem dobrego przybliżenia. Postgres właśnie to daje i będzie znacznie szybszy, ponieważ nie będzie musiał oceniać każdego wiersza:
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;
Właściwie nie jestem pewien, czy istnieje korzyść z eksternalizacji
RIGHT JOIN
lub posiadania go tak, jak w standardowym zapytaniu. Zasługiwałoby na testy.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 ?
źródło
WHERE
klauzulą w twoich zapytaniach. Drugie zapytanie jest logicznie błędne (pobiera jeden wiersz dla każdej tabeli w bazie danych) - i droższe, gdy zostanie naprawione.Jest to zła praktyka wywoływanie dwa razy tego samego zapytania w celu uzyskania całkowitej liczby wierszy wyniku końcowego. Zajmie to czas wykonania i zmarnuje zasoby serwera.
Lepiej, możesz użyć
SQL_CALC_FOUND_ROWS
w zapytaniu, które powie MySQL, aby pobierał całkowitą liczbę wierszy wraz z limitami wyników zapytania.Przykład ustawiony jako:
SELECT SQL_CALC_FOUND_ROWS employeeName, phoneNumber FROM employee WHERE employeeName LIKE 'a%' LIMIT 10; SELECT FOUND_ROWS();
W powyższym zapytaniu wystarczy dodać
SQL_CALC_FOUND_ROWS
opcję w pozostałym wymaganym zapytaniu i wykonać drugą linię, tj.SELECT FOUND_ROWS()
Zwraca liczbę wierszy w zestawie wyników zwróconych przez tę instrukcję.źródło
Nie.
Być może jest pewien niewielki zysk, który teoretycznie można uzyskać, uruchamiając je pojedynczo z wystarczająco skomplikowaną maszyną pod maską. Ale jeśli chcesz wiedzieć, ile wierszy pasuje do warunku, musisz je policzyć, a nie tylko OGRANICZONY podzbiór.
źródło