2017-05-05 10 views
5

Rozważmy następującą kwerendę sql:Inteligentne zapytań logicznych przy wykorzystaniu funkcji wewnątrz PostgreSQL

SELECT a,b,c 
FROM t 
WHERE (id1 = :p_id1 OR :p_id1 IS NULL) AND (id2 = :p_id2 OR :p_id2 IS NULL) 

Markus Winand w swojej książce „SQL Performance explained” names to podejście jako jeden z najgorszych wyników anty-wzorców wszech i wyjaśnia dlaczego (baza danych musi przygotować plan na najgorszy przypadek, gdy wszystkie filtry są wyłączone).

Ale później pisze również, że dla PostgreSQL ten problem występuje tylko przy ponownym użyciu instrukcji (PreparedStatement) obsługi.

Załóżmy też teraz, że zapytanie to jest zawinięty do funkcji, coś jak:

CREATE FUNCTION func(IN p_id1 BIGINT,IN p_id2 BIGINT) 
... 
$BODY$ 
    BEGIN 
    ... 
    END; 
$BODY$ 

tej pory mam niezrozumienie kilku punktach:

  1. Czy ten problem nadal występuje w przypadku funkcja owijania? (Próbowałem zobaczyć plan wykonania dla wywołania funkcji, ale Postgres nie pokazuje mi szczegółów wewnętrznych wywołań funkcji, nawet z SET auto_explain.log_nested_statements = ON).

  2. Załóżmy, że pracuję nad starszym projektem i nie mogę zmienić samej funkcji, tylko kod wykonawczy Java. Czy lepiej będzie unikać tutaj przygotowanego wyciągu i za każdym razem używać zapytania dynamicznego? (Zakładając, że czas wykonania jest dość długi, do kilku sekund). Powiedzieć, prawdopodobnie brzydki podejście:


getSession().doWork(connection -> { 
    ResultSet rs = connection.createStatement().executeQuery("select * from func("+id1+","+id2+")"); 
    ... 
}) 

Odpowiedz

2

1. To zależy.

Gdy nie używasz gotowych instrukcji, PostgreSQL planuje zapytanie za każdym razem od nowa, używając wartości parametrów. Jest znany jako niestandardowy plan .

Z przygotowanymi instrukcjami (i masz rację, funkcje PL/pgSQL używają przygotowanych instrukcji) jest to bardziej skomplikowane. PostgreSQL przygotowuje instrukcję (analizuje jej tekst i przechowuje drzewo analizy), ale ponownie ją planuje za każdym razem, gdy jest wykonywana. Plany niestandardowe są generowane co najmniej 5 razy. Następnie planista rozważa użycie ogólnego planu ( (tzn. Niezależnego od parametru), jeśli jego koszt jest niższy niż średni koszt wygenerowanych do tej pory planów niestandardowych.

Pamiętaj, że koszt abonamentu to oszacowanie planisty, a nie rzeczywiste operacje we/wy lub cykle procesora.

Wystąpił problem z z, ale potrzebujesz na to pecha.

2. Zaproponowane podejście nie zadziała, ponieważ nie zmienia zachowania funkcji.

Generalnie nie jest tak brzydkie, aby PostgreSQL nie używał parametrów (jak to jest na przykład z Oracle), ponieważ PostgreSQL nie ma współużytkowanej pamięci podręcznej dla planów. Przygotowane plany są przechowywane w pamięci każdego backendu, więc ponowne planowanie nie wpłynie na inne sesje.

Z tego co wiem, obecnie nie ma możliwości zmuszenia planisty do korzystania z niestandardowych planów (innych niż ponowne połączenie po 5 egzekucjach ...).

+0

Dziękujemy za odpowiedź. Odnośnie pierwszego punktu, nie do końca rozumiem. Czy to oznacza, że ​​opisany problem ogólnie nie jest problemem dla PostgreSQL, gdy tego typu zapytania są pakowane w funkcję? – Andremoniy

+0

To naprawdę zależy od szczęścia. Powiedzmy, że zapytanie ma jeden parametr i bardzo potrzebuje różnych planów dla wartości A i B. Na przykład A prosi o skanowanie sekwencyjne (wysokie koszty), a B korzysta ze skanowania indeksu (niski koszt). Ogólny plan wykorzystuje skanowanie sekwencyjne. Wykonujesz F (A) 5 razy, a planista decyduje, że można przejść do planu ogólnego. Teraz masz problem: F (B) nie użyje skanowania indeksu. Ale jeśli zadzwonisz do F (A), F (B), F (A), F (B) i tak dalej, średni koszt własny będzie mniejszy niż koszt ogólnego planu i jesteś bezpieczny. –

+0

Dobra, ale myślę, że zawsze powinniśmy rozważyć najgorszy przypadek, nieprawdaż? Wygląda na to, że w najgorszym przypadku nadal będzie to problemem. I czy poprawnie rozumiem, że dla funkcji plan zostanie obliczony niezależnie od użycia przygotowanego wyciągu? – Andremoniy

Powiązane problemy