Wychodząc z tła MySQL, gdzie wydajność procedury przechowywanej (starszy artykuł) i użyteczność są wątpliwe, oceniam PostgreSQL pod kątem nowego produktu dla mojej firmy.
Jedną z rzeczy, które chciałbym zrobić, jest przeniesienie logiki aplikacji do procedur przechowywanych, więc tutaj proszę o DOs i DON'T (najlepsze praktyki) dotyczące korzystania z funkcji w PostgreSQL (9.0), szczególnie w odniesieniu do pułapek wydajności.
postgresql
best-practices
plpgsql
Derek Downey
źródło
źródło
Odpowiedzi:
Ściśle mówiąc, termin „procedury przechowywane” wskazuje na procedury SQL w Postgres, wprowadzone w Postgres 11. Powiązane:
Są też funkcje , które działają prawie, ale nie do końca tak samo, i były tam od samego początku.
Funkcje z
LANGUAGE sql
są w zasadzie tylko plikami wsadowymi z prostymi poleceniami SQL w opakowaniu funkcji (a zatem atomowym, zawsze uruchamianym w ramach pojedynczej transakcji) akceptującym parametry. Wszystkie instrukcje w funkcji SQL są planowane jednocześnie , co nieznacznie różni się od wykonywania jednej instrukcji po drugiej i może wpływać na kolejność wykonywania blokad.Co więcej, najbardziej dojrzałym językiem jest PL / pgSQL (
LANGUAGE plpgsql
). Działa dobrze i był ulepszany z każdym wydaniem w ciągu ostatniej dekady, ale najlepiej służy jako klej do poleceń SQL. Nie jest przeznaczony do ciężkich obliczeń (innych niż polecenia SQL).Funkcje PL / pgSQL wykonują zapytania takie jak przygotowane instrukcje . Ponowne użycie buforowanych planów zapytań zmniejsza część kosztów związanych z planowaniem i czyni je nieco szybszymi niż równoważne instrukcje SQL, co może być zauważalnym efektem w zależności od okoliczności. Może mieć również skutki uboczne, jak w tym powiązanym pytaniu:
Niesie to zalety i wady przygotowanych wypowiedzi - jak omówiono w instrukcji . W przypadku zapytań o tabele z nieregularnym rozkładem danych i zmiennymi parametrami dynamiczny SQL z
EXECUTE
może działać lepiej, gdy zysk ze zoptymalizowanego planu wykonania dla danego parametru (parametrów) przewyższa koszt ponownego planowania.Ponieważ ogólne plany wykonania Postgres 9.2 są nadal buforowane dla sesji, ale cytując instrukcję :
Przez większość czasu uzyskujemy to, co najlepsze z obu światów (pomniejszone o dodatkowe koszty ogólne) bez użycia (ab)
EXECUTE
. Szczegóły w Co nowego w PostgreSQL 9.2 na PostgreSQL Wiki .Postgres 12 wprowadza dodatkową zmienną serwera,
plan_cache_mode
aby wymusić plany ogólne lub niestandardowe. W szczególnych przypadkach należy zachować ostrożność.Możesz wygrać duże dzięki funkcjom po stronie serwera, które zapobiegają dodatkowym objazdom do serwera bazy danych z Twojej aplikacji. Niech serwer wykona jak najwięcej zadań jednocześnie i zwróci tylko dobrze określony wynik.
Unikaj zagnieżdżania złożonych funkcji, zwłaszcza funkcji tabel (
RETURNING SETOF record
lubTABLE (...)
). Funkcje to czarne skrzynki, które stanowią bariery optymalizacyjne w narzędziu do planowania zapytań. Są one optymalizowane osobno, nie w kontekście zewnętrznego zapytania, co ułatwia planowanie, ale może skutkować mniej niż doskonałymi planami. Ponadto kosztów i wielkości wyników funkcji nie można wiarygodnie przewidzieć.Wyjątkiem od tej reguły są proste funkcje SQL (
LANGUAGE sql
), które mogą być „inline” - jeśli zostaną spełnione pewne warunki . Przeczytaj więcej o tym, jak działa narzędzie do planowania zapytań w tej prezentacji autorstwa Neila Conwaya (zaawansowane rzeczy).W PostgreSQL funkcja zawsze działa automatycznie w ramach jednej transakcji . Wszystko się udaje lub nic. Jeśli wystąpi wyjątek, wszystko jest wycofywane. Ale jest obsługa błędów ...
Dlatego też funkcje nie są dokładnie „procedurami składowanymi” (nawet jeśli termin ten jest czasem wprowadzany w błąd). Niektóre polecenia podoba
VACUUM
,CREATE INDEX CONCURRENTLY
czyCREATE DATABASE
nie można uruchomić wewnątrz bloku transakcji, więc nie są one dozwolone w funkcji. (Ani w procedurach SQL, jak na Postgres 11. To może zostać dodane później.)Przez lata napisałem tysiące funkcji plpgsql.
źródło
Niektóre DO:
źródło
Mówiąc ogólnie, przeniesienie logiki aplikacji do bazy danych oznacza, że jest szybsza - w końcu będzie działać bliżej danych.
Uważam (ale nie jestem w 100% pewien), że funkcje języka SQL są szybsze niż te używające innych języków, ponieważ nie wymagają przełączania kontekstu. Minusem jest to, że logika proceduralna nie jest dozwolona.
PL / pgSQL jest najbardziej dojrzałym i kompletnym z wbudowanych języków - ale w celu zwiększenia wydajności można użyć C (choć przyniesie to tylko korzyści obliczeniowe)
źródło
Możesz zrobić kilka bardzo interesujących rzeczy za pomocą funkcji zdefiniowanych przez użytkownika (UDF) w postgresql. Na przykład możesz użyć dziesiątek możliwych języków. Wbudowane pl / sql i pl / pgsql są zarówno zdolne, jak i niezawodne i wykorzystują metodę piaskownicy, aby powstrzymać użytkowników od robienia czegokolwiek zbyt strasznie niebezpiecznego. UDF napisane w C zapewniają najwyższą moc i wydajność, ponieważ działają w tym samym kontekście co sama baza danych. To jednak jak zabawa z ogniem, ponieważ nawet małe błędy mogą powodować ogromne problemy, awarie backendów lub dane. Języki custome pl, takie jak pl / R, pl / ruby, pl / perl itd. Zapewniają możliwość pisania zarówno warstw bazy danych, jak i aplikacji w tych samych językach. Może to być przydatne, ponieważ oznacza to, że nie musisz uczyć java programisty perla lub pl / pgsql itp., Aby pisać UDF.
Na koniec jest język pl / proxy . Ten język UDF umożliwia uruchamianie aplikacji na kilkudziesięciu lub więcej serwerach postgresql zaplecza w celu skalowania. Został opracowany przez dobrych ludzi ze Skype i zasadniczo pozwala na rozwiązanie skalowania poziomego biednego człowieka. Zaskakująco łatwo jest też pisać.
A teraz kwestia wydajności. To jest szary obszar. Czy piszesz aplikację dla jednej osoby? A może za 1000? lub za 10 000 000? Sposób, w jaki zbudujesz swoją aplikację i użyjesz UDF, zależeć będzie WIELE od tego, jak próbujesz skalować. Jeśli piszesz dla tysięcy użytkowników, główną rzeczą, którą chcesz zrobić, jest jak najbardziej zmniejszyć obciążenie bazy danych. UDF, które zmniejszają ilość danych przenoszonych z powrotem do bazy danych, pomogą zmniejszyć obciążenie IO. Jeśli jednak zaczną zwiększać obciążenie procesora, mogą stanowić problem. Ogólnie mówiąc, priorytetem jest zmniejszenie obciążenia IO, a następnie upewnienie się, że UDF są wydajne, aby nie przeciążać procesorów.
źródło