Mam zapytanie o system Postgresql 9.2, który zajmuje około 20 w swojej normalnej postaci, ale zajmuje tylko ~ 120 ms przy użyciu CTE.Czy istnieje logicznie równoważna i wydajna wersja tego zapytania bez użycia CTE?
Uprościliśmy oba zapytania pod kątem zwięzłości.
Oto postaci normalnej (trwa około 20 lat)
SELECT *
FROM tableA
WHERE (columna = 1 OR columnb = 2) AND
atype = 35 AND
aid IN (1, 2, 3)
ORDER BY modified_at DESC
LIMIT 25;
Oto wyjaśnienia tego zapytania: http://explain.depesz.com/s/2v8
Postać CTE (około 120ms):
WITH raw AS (
SELECT *
FROM tableA
WHERE (columna = 1 OR columnb = 2) AND
atype = 35 AND
aid IN (1, 2, 3)
)
SELECT *
FROM raw
ORDER BY modified_at DESC
LIMIT 25;
Oto wyjaśnienie CTE: http://explain.depesz.com/s/uxy
Po prostu przesuwając ORDER BY
do zewnętrznej części zapytania zmniejsza koszt o 99%.
Mam dwa pytania: 1) czy istnieje sposób na skonstruowanie pierwszego zapytania bez użycia CTE w taki sposób, aby był logicznie równoważny bardziej wydajny i 2) co ta różnica w wydajności mówi o tym, jak planista jest ustalanie sposobu pobierania danych?
Co do powyższych pytań, czy istnieją dodatkowe statystyki lub inne wskazówki dla planistów, które pomogłyby poprawić wydajność pierwszego zapytania?
Edytuj: Usunięcie limitu powoduje również, że w zapytaniu używane jest skanowanie sterty, a nie skanowanie indeksu do tyłu. Bez zapytania LIMIT
zapytanie kończy się w ciągu 40 ms.
Po obejrzeniu efektu LIMIT
Próbowałem z LIMIT 1
, LIMIT 2
itd Zapytanie wykonuje w ramach 100ms przy użyciu LIMIT 1
i 10s + z LIMIT
> 1.
Po myśleć o tym trochę więcej, pytanie 2 wrze do tego, dlaczego planista używa skanowania indeksu do tyłu w jednym przypadku, a stertę bitmapową skanuje i sortuje w innym logicznie równoważnym przypadku? A jak mogę "pomóc" planiście w efektywnym planowaniu w obu przypadkach?
Aktualizacja: przyjąłem odpowiedź Craiga, ponieważ był to najbardziej wszechstronna i pomocny. Sposób w jaki rozwiązałem problem polegał na zastosowaniu zapytania, które było praktycznie równoważne, ale nie logicznie równoważne. U źródła problemu znajdował się indeks skanowany do tyłu indeksu na modified_at. Aby poinformować planistę, że nie jest to dobry pomysł, dodam predykat formularza WHERE modified_at >= NOW() - INTERVAL '1 year'
. Obejmowało to wystarczającą ilość danych dla aplikacji, ale uniemożliwiło planerowi przejście w dół ścieżki skanowania indeksu wstecznego.
To było znacznie mniej skuteczne rozwiązanie, które zapobiegło konieczności przepisywania zapytań za pomocą sub zapytania lub CTE. YMMV.
dziękuję, chociaż użyłem tej własności (jest to przypadek) Nie wiedziałem, że PostgreSQL nie optymalizuje się na granicach CTE. Jeśli spojrzysz na przedstawione przeze mnie plany wyjaśniające, nie wydaje ci się, że używane są znaczące ilości 'work_mem' (~ 25k). Większość kosztów pochodzi ze skanowania indeksu wstecz. – drsnyder
@drsnyder Oh! Źle przeczytałem! 20s i 120ms. Ponownie przeczytam i poprawię odpowiedź odpowiednio. –
@drsnyder Ponownie napisane. Nadzieja, która ma więcej sensu. Proszę pokazać wyjście z http://wiki.postgresql.org/wiki/Server_Configuration tylko po to, aby potwierdzić, że nie masz żadnych parautów 'enable_', itp., Ale wygląda to trochę na podejrzany wybór przez planistę. –