PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Dlaczego PostgreSQL wielokrotnie wywołuje moją funkcję STABILNA/NIEZMIENNA?

Poniższe rozszerzenie kodu testowego ma charakter informacyjny:

CREATE OR REPLACE FUNCTION test_multi_calls1(one integer)
RETURNS integer
AS $BODY$
BEGIN
    RAISE NOTICE 'Immutable called with %', one;
    RETURN one;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION test_multi_calls2(one integer)
RETURNS integer
AS $BODY$
BEGIN
    RAISE NOTICE 'Volatile called with %', one;
    RETURN one;
END;
$BODY$ LANGUAGE plpgsql VOLATILE;

WITH data AS
(
    SELECT 10 AS num
    UNION ALL SELECT 10
    UNION ALL SELECT 20
)
SELECT test_multi_calls1(num)
FROM data
where test_multi_calls2(40) = 40
and test_multi_calls1(30) = 30

WYJŚCIE:

NOTICE:  Immutable called with 30
NOTICE:  Volatile called with 40
NOTICE:  Immutable called with 10
NOTICE:  Volatile called with 40
NOTICE:  Immutable called with 10
NOTICE:  Volatile called with 40
NOTICE:  Immutable called with 20

Tutaj widzimy, że podczas gdy na liście wyboru funkcja niezmienna była wywoływana wiele razy, w klauzuli where została wywołana raz, podczas gdy funkcja volatile została wywołana trzykrotnie.

Ważne nie jest to, że PostgreSQL wywoła tylko STABLE lub IMMUTABLE funkcjonować raz z tymi samymi danymi – Twój przykład wyraźnie pokazuje, że tak nie jest – po prostu może nazwij to tylko raz. A może wywoła go dwukrotnie, gdy będzie musiał wywołać wersję lotną 50 razy i tak dalej.

Istnieją różne sposoby wykorzystania stabilności i niezmienności, z różnymi kosztami i korzyściami. Aby zapewnić rodzaj zapisywania, który sugerujesz, powinien wykonać z listami wyboru, musiałby buforować wyniki, a następnie wyszukać każdy argument (lub listę argumentów) w tej pamięci podręcznej przed zwróceniem wyniku z pamięci podręcznej lub wywołaniem funkcji w pamięci podręcznej -tęsknić. Byłoby to droższe niż wywołanie funkcji, nawet w przypadku wysokiego odsetka trafień w pamięci podręcznej (może być 0% trafień w pamięci podręcznej, co oznacza, że ​​ta „optymalizacja” wykonała dodatkową pracę bez żadnego zysku). Może przechowywać może tylko ostatni parametr i wynik, ale znowu może to być całkowicie bezużyteczne.

Jest to szczególnie ważne, biorąc pod uwagę, że stabilne i niezmienne funkcje są często najlżejszymi funkcjami.

Jednak z klauzulą ​​where niezmienność test_multi_calls1 pozwala PostgreSQL na rzeczywistą restrukturyzację zapytania z prostego znaczenia podanego SQL:

Do zupełnie innego planu zapytań:

Jest to rodzaj zastosowania, jakie PostgreSQL wykorzystuje ze STABLE i IMMUTABLE - nie buforowanie wyników, ale przepisywanie zapytań na różne zapytania, które są bardziej wydajne, ale dają te same wyniki.

Zauważ również, że test_multi_calls1(30) jest wywoływany przed test_multi_calls2(40) bez względu na kolejność ich występowania w klauzuli where. Oznacza to, że jeśli pierwsze wywołanie nie spowoduje zwrócenia żadnych wierszy (zastąp = 30 z = 31 do przetestowania), wtedy funkcja volatile nie zostanie w ogóle wywołana - ponownie, niezależnie od tego, która jest po której stronie and .

Ten szczególny rodzaj przepisywania zależy od niezmienności lub stabilności. Z where test_multi_calls1(30) != num Przepisywanie zapytań nastąpi dla funkcji niezmiennych, ale nie tylko dla funkcji stabilnych. Z where test_multi_calls1(num) != 30 to się w ogóle nie stanie (wiele połączeń), chociaż możliwe są inne optymalizacje:

Wyrażenia zawierające tylko funkcje STABILNE i NIEZMIENNE mogą być używane ze skanowaniem indeksu. Wyrażenia zawierające funkcje VOLATILE nie mogą. Liczba wywołań może się zmniejszyć lub nie, ale o wiele ważniejsze jest to, że wyniki wywołań będą wtedy wykorzystywane w znacznie wydajniejszy sposób w pozostałej części zapytania (istnieje tylko w przypadku dużych tabel, ale wtedy może to spowodować ogromne różnica).

Podsumowując, nie myśl o kategoriach zmienności w kategoriach zapamiętywania, ale raczej w kategoriach dawania planerowi zapytań PostgreSQL możliwości restrukturyzowania całych zapytań w sposób, który jest logicznie równoważny (te same wyniki), ale o wiele bardziej wydajny.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Znajdź źródło zapytania przez pgbouncer

  2. Jak uniknąć wielu ewaluacji funkcji za pomocą składni (func()).* w zapytaniu SQL?

  3. PostgreSQL - uruchom dwie transakcje jednocześnie

  4. Narzędzie do konwersji procedury składowanej t-sql (SQL Server) na pgsql (postgre sql)

  5. Dołącz do CTE w SQLAlchemy