Poniżej znajduje się fragment książki o projekcie db (Początkowy projekt bazy danych ISBN: 0-7645-7490-6):
Niebezpieczeństwo związane z używaniem widoków polega na filtrowaniu zapytania względem widoku, spodziewając się odczytania bardzo małej części bardzo dużej tabeli. Wszelkie filtrowanie powinno odbywać się w widoku, ponieważ wszelkie filtrowanie względem samego widoku jest stosowane po zakończeniu wykonywania zapytania w widoku. Widoki są zwykle przydatne do przyspieszenia procesu programowania, ale na dłuższą metę mogą całkowicie zabić wydajność bazy danych.
Oto fragment dokumentacji PostgreSQL 9.5:
Liberalne wykorzystanie widoków jest kluczowym aspektem dobrego projektu bazy danych SQL. Widoki pozwalają na zawarcie w szczegółach struktury tabel, które mogą się zmieniać w miarę ewolucji aplikacji, za spójnymi interfejsami.
Te dwa źródła wydają się ze sobą sprzeczne („nie projektuj z widokami” vs. „projektuj z widokami”).
Jednak w PG widoki są implementowane przy użyciu systemu reguł. Być może (i to jest moje pytanie) każde filtrowanie w stosunku do widoku jest przepisywane jako filtr w widoku, co powoduje wykonanie pojedynczego zapytania względem bazowych tabel.
Czy moja interpretacja jest poprawna, a PG łączy klauzule GDZIE w widoku i poza nim? Czy też uruchamia je osobno, jeden po drugim? Jakieś krótkie, samodzielne, poprawne (kompilowalne) przykłady?
SELECT * FROM my_view WHERE my_column = 'blablabla';
Podczas gdy drugi dotyczy korzystania z widoków, aby model danych był przezroczysty dla aplikacji, która go używa. Pierwsze źródła wskazują, że należy uwzględnić filtrWHERE my_column = 'blablabla'
w definicji widoku, ponieważ zapewnia to lepszy plan wykonania.Odpowiedzi:
Książka jest zła.
Wybieranie z widoku jest dokładnie tak szybkie lub wolne, jak uruchomienie bazowej instrukcji SQL - możesz to łatwo sprawdzić za pomocą
explain analyze
.Optymalizator Postgres (i optymalizator dla wielu innych nowoczesnych DBMS) będzie w stanie przesuwać predykaty widoku do rzeczywistej instrukcji widoku - pod warunkiem, że jest to prosta instrukcja (ponownie, można to zweryfikować za pomocą
explain analyze
).„Zła reputacja” związana z wydajnością wynika - jak sądzę - z momentu, gdy nadużywasz widoków i zaczynasz budować widoki, które wykorzystują widoki, które korzystają z widoków. Bardzo często skutkuje to stwierdzeniami, które robią za dużo w porównaniu do instrukcji, które zostały ręcznie dopasowane bez widoków, np. Ponieważ niektóre tabele pośrednie nie byłyby potrzebne. W prawie wszystkich przypadkach optymalizator nie jest wystarczająco inteligentny, aby usunąć niepotrzebne tabele / sprzężenia lub przesuwać predykaty na wielu poziomach widoków (dotyczy to również innych DBMS).
źródło
explain analyze
oświadczenia?Aby dać przykład , co @a_horse wyjaśnił :
Postgres implementuje schemat informacyjny, który składa się z (czasem skomplikowanych) widoków dostarczających informacji o obiektach DB w znormalizowanej formie. Jest to wygodne i niezawodne - i może być znacznie droższe niż bezpośredni dostęp do tabel katalogu Postgres.
Bardzo prosty przykład, aby uzyskać wszystkie widoczne kolumny tabeli
... ze schematu informacyjnego:
... z katalogu systemowego:
Porównaj plany zapytań i czas wykonania dla obu
EXPLAIN ANALYZE
.Pierwsze zapytanie opiera się na widoku
information_schema.columns
, który łączy się z wieloma tabelami, których wcale nie potrzebujemy.Drugie zapytanie skanuje tylko jedną tabelę
pg_catalog.pg_attribute
, a więc znacznie szybciej. (Ale pierwsze zapytanie nadal wymaga tylko kilku ms we wspólnych bazach danych).Detale:
źródło
EDYTOWAĆ:
Z przeprosinami muszę wycofać moje twierdzenie, że zaakceptowana odpowiedź nie zawsze jest poprawna - stwierdza, że widok jest zawsze identyczny z tym samym, napisanym jako podzapytanie. Myślę, że to bezdyskusyjne i myślę, że teraz wiem, co się dzieje w moim przypadku.
Myślę też, że jest lepsza odpowiedź na pierwotne pytanie.
Pierwotne pytanie dotyczy tego, czy korzystanie z widoków powinno być przewodnią praktyką (w przeciwieństwie do na przykład powtarzania SQL w procedurach, które mogą wymagać utrzymania dwa lub więcej razy).
Moja odpowiedź brzmiałaby: „nie, jeśli zapytanie używa funkcji okna lub czegokolwiek innego, co powoduje, że optymalizator traktuje zapytanie inaczej, gdy staje się ono podzapytaniem, ponieważ sam akt tworzenia podzapytania (reprezentowanego jako widok lub nie) może obniżyć wydajność jeśli filtrujesz za pomocą parametrów w czasie wykonywania.
Złożoność mojej funkcji okna jest niepotrzebna. Wyjaśnij plan:
jest o wiele tańszy niż w tym przypadku:
Mam nadzieję, że jest to bardziej szczegółowe i pomocne.
Z mojego ostatniego doświadczenia (powodującego, że znalazłem to pytanie), powyższa zaakceptowana odpowiedź jest nieprawidłowa we wszystkich okolicznościach. Mam stosunkowo proste zapytanie, które obejmuje funkcję okna:
Jeśli dodam ten filtr:
Wyjaśniam plan, który otrzymuję:
Wykorzystuje się w tym indeks klucza podstawowego w tabeli obsługi pociągu i nieunikalny indeks w tabelipart_consist. Wykonuje się w 90ms.
Utworzyłem widok (wklejając go tutaj, aby był absolutnie jasny, ale dosłownie jest to zapytanie w widoku):
Kiedy pytam ten widok z identycznym filtrem:
Oto plan wyjaśniania:
Robi to pełne skanowanie obu tabel i zajmuje 17 sekund.
Dopóki się z tym nie spotkałem, swobodnie korzystałem z widoków w PostgreSQL (po zrozumieniu szeroko rozpowszechnionych poglądów wyrażonych w zaakceptowanej odpowiedzi). W szczególności unikałbym korzystania z widoków, jeśli potrzebuję filtrowania wstępnego agregacji, dla którego używałbym funkcji zwracających zestaw.
Wiem również, że CTE w PostgreSQL są ściśle oceniane osobno, z założenia, więc nie używam ich w taki sam sposób, jak na przykład w SQL Server, gdzie wydają się być zoptymalizowane jako podkwerendy.
Moja odpowiedź brzmi zatem: są przypadki, w których widoki nie działają dokładnie tak, jak zapytanie, na którym są oparte, dlatego zaleca się ostrożność. Korzystam z Amazon Aurora opartej na PostgreSQL 9.6.6.
źródło
CASE WHEN (NOT ts.primary_direction) THEN '-1' :: INTEGER ELSE 1 END
niepotrzebnie sprawi, że zapytanie będzie wolniejsze niż potrzeba , ponieważ lepiej jest napisać dwa kolejne warunki warunkowe w kolejności.CASE WHEN (NOT ts.primary_direction) THEN dense_rank() OVER (PARTITION BY ts.train_service_key ORDER BY pc.through_idx DESC, pc.first_portion ASC, pc.first_seq DESC) ELSE dense_rank() OVER (PARTITION BY ts.train_service_key ORDER BY pc.through_idx DESC, pc.first_portion ASC, pc.first_seq ASC) END AS coach_block_idx
dense_rank()
więc nie jest to tak naprawdę problem z wydajnością.(Jestem wielkim fanem widoków, ale musisz być bardzo ostrożny z PG tutaj i chciałbym zachęcić wszystkich do korzystania z widoków ogólnie również w PG dla lepszej zrozumiałości i łatwości obsługi zapytań / kodu)
Właściwie i niestety (OSTRZEŻENIE :) używanie widoków w Postgresie spowodowało nam poważne problemy i znacznie obniżyło naszą wydajność w zależności od funkcji, których używaliśmy wewnątrz :-( (przynajmniej z wersją 10.1). (Nie byłoby tak w przypadku innych nowoczesne systemy DB, takie jak Oracle.)
(W zależności od tego, co dokładnie masz na myśli - nie - można zmaterializować pośrednie tabele temperatur, których możesz nie chcieć lub gdzie predykaty nie są spychane w dół ...)
Znam co najmniej dwie główne „funkcje”, które zawiodły nas w trakcie migracji z Oracle do Postgres, więc musieliśmy porzucić PG w projekcie:
CTE (
with
-klauzulazy / wspólne wyrażenia tabelowe ) są (zwykle) przydatne do konstruowania bardziej złożonych zapytań (nawet w mniejszych aplikacjach), ale w PG są z założenia zaimplementowane jako „ukryte” wskazówki optymalizatora (generujące np. Nieindeksowane tabele temp) i dlatego naruszają (dla mnie i wielu innych ważnych) koncepcję deklaratywnego SQL ( Oracle docu ): npproste zapytanie:
przepisane przy użyciu CTE:
dalsze źródła z dyskusjami itp .: https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/
funkcje okna z
over
-statements są potencjalnie bezużyteczne (zwykle używane w widokach, np. jako źródło raportów opartych na bardziej złożonych zapytaniach)nasze obejście
with
klauzulPrzekształcimy wszystkie „widoki wbudowane” w prawdziwe widoki ze specjalnym prefiksem, aby nie zakłócały listy / przestrzeni nazw widoków i mogą być łatwo powiązane z oryginalnym „widokiem zewnętrznym”: - /
nasze rozwiązanie dla funkcji okna
Z powodzeniem zaimplementowaliśmy go przy użyciu bazy danych Oracle.
źródło