W tym doskonałym pytaniu SO omówiono różnice między CTE
i sub-queries
.
Chciałbym konkretnie zapytać:
W jakich okolicznościach każde z poniższych jest bardziej wydajne / szybsze?
- CTE
- Pod-zapytanie
- Stół tymczasowy
- Zmienna tabeli
Tradycyjnie używałem dużo do temp tables
programowania stored procedures
- ponieważ wydają się one bardziej czytelne niż wiele powiązanych ze sobą zapytań cząstkowych.
Non-recursive CTE
s bardzo dobrze enkapsulują zestawy danych i są bardzo czytelne, ale czy istnieją szczególne okoliczności, w których można powiedzieć, że zawsze będą działały lepiej? czy może zawsze trzeba bawić się z różnymi opcjami, aby znaleźć najbardziej wydajne rozwiązanie?
EDYTOWAĆ
Ostatnio powiedziano mi, że pod względem wydajności tabele tymczasowe są dobrym wyborem, ponieważ mają powiązany histogram, tj. Statystyki.
Odpowiedzi:
SQL jest językiem deklaratywnym, a nie językiem proceduralnym. Oznacza to, że konstruujesz instrukcję SQL, aby opisać pożądane wyniki. Nie mówisz silnikowi SQL, jak wykonać tę pracę.
Zasadniczo dobrym pomysłem jest pozwolić silnikowi SQL i optymalizatorowi SQL na znalezienie najlepszego planu zapytań. Opracowanie silnika SQL wymaga wielu osobo-letnich starań, więc niech inżynierowie zrobią to, co umieją.
Oczywiście zdarzają się sytuacje, w których plan zapytań nie jest optymalny. Następnie chcesz użyć wskazówek dotyczących zapytania, zrestrukturyzować zapytanie, zaktualizować statystyki, użyć tabel tymczasowych, dodać indeksy itp., Aby uzyskać lepszą wydajność.
Co do twojego pytania. Wydajność CTE i podzapytań powinna teoretycznie być taka sama, ponieważ oba zapewniają te same informacje optymalizatorowi zapytań. Jedną różnicą jest to, że CTE użyte więcej niż jeden raz można łatwo zidentyfikować i obliczyć raz. Wyniki można następnie zapisać i odczytać wiele razy. Niestety, SQL Server nie wydaje się korzystać z tej podstawowej metody optymalizacji (można to nazwać wspólną eliminacją podzapytań).
Tabele tymczasowe to inna sprawa, ponieważ zapewniasz więcej wskazówek na temat uruchamiania zapytania. Jedną z głównych różnic jest to, że optymalizator może wykorzystać statystyki z tabeli tymczasowej do ustalenia swojego planu zapytań. Może to spowodować wzrost wydajności. Ponadto, jeśli masz skomplikowane CTE (podzapytanie), które jest używane więcej niż jeden raz, wówczas przechowywanie go w tabeli tymczasowej często zapewnia zwiększenie wydajności. Zapytanie jest wykonywane tylko raz.
Odpowiedź na twoje pytanie brzmi: musisz się pobawić, aby uzyskać oczekiwaną wydajność, szczególnie w przypadku złożonych zapytań, które są uruchamiane regularnie. W idealnym świecie optymalizator zapytań znalazłby idealną ścieżkę wykonania. Chociaż często tak się dzieje, możesz znaleźć sposób na uzyskanie lepszej wydajności.
źródło
Nie ma reguły. Uważam, że CTE są bardziej czytelne i używam ich, chyba że wykazują pewne problemy z wydajnością, w takim przypadku badam rzeczywisty problem, a nie domyślam się, że CTE jest problemem i próbuję go napisać inaczej, stosując inne podejście. Zazwyczaj chodzi o coś więcej niż sposób, w jaki zdecydowałem się zadeklarować moje zamiary za pomocą zapytania.
Z pewnością istnieją przypadki, w których można rozwikłać CTE lub usunąć podzapytania i zastąpić je tabelą #temp i skrócić czas trwania. Może to wynikać z różnych rzeczy, takich jak nieaktualne statystyki, niemożność uzyskania nawet dokładnych statystyk (np. Połączenie z funkcją o wartościach w tabeli), równoległość lub nawet niemożność wygenerowania optymalnego planu z powodu złożoności zapytania ( w takim przypadku jego rozbicie może dać optymalizatorowi szansę na walkę). Ale są też przypadki, w których operacje we / wy związane z tworzeniem tabeli temperatur mogą przewyższać inne aspekty wydajności, które mogą sprawić, że dany kształt planu będzie mniej atrakcyjny przy użyciu CTE.
Szczerze mówiąc, istnieje zbyt wiele zmiennych, aby zapewnić „poprawną” odpowiedź na twoje pytanie. Nie ma przewidywalnego sposobu dowiedzenia się, kiedy zapytanie może przechylić się na korzyść takiego czy innego podejścia - po prostu wiedz, że teoretycznie ta sama semantyka dla CTE lub pojedynczego podzapytania powinna wykonać dokładnie to samo. Myślę, że twoje pytanie byłoby bardziej wartościowe, jeśli przedstawisz niektóre przypadki, w których nie jest to prawdą - może być tak, że odkryłeś ograniczenie w optymalizatorze (lub odkryłeś znane), lub może być tak, że twoje zapytania nie są semantycznie równoważne lub ten zawiera element, który udaremnia optymalizację.
Sugeruję więc napisanie zapytania w sposób, który wydaje ci się najbardziej naturalny, i odbiegać tylko wtedy, gdy odkryjesz rzeczywisty problem z wydajnością, jaki ma optymalizator. Osobiście oceniam je według CTE, a następnie podzapytania, przy czym tablica #temp jest ostatecznością.
źródło
link / edit / close / flag
- jeśli były głosy, by zamknąć pytanie, zobaczyszclose (n)
gdzien
reprezentuje liczbę użytkowników, którzy głosowali za zamknięciem twojego pytania. Po kliknięciu linku zobaczysz powody, dla których użytkownicy zostali wybrani.#temp jest zmaterializowany, a CTE nie.
CTE to tylko składnia, więc teoretycznie jest to tylko podzapytanie. Jest wykonywany. #temp jest zmaterializowany. Dlatego kosztowne CTE w łączeniu, które jest wykonywane wielokrotnie, może być lepsze w #temp. Z drugiej strony, jeśli jest to łatwa ocena, która nie jest wykonywana, ale kilka razy, to nie jest warta narzutu #temp.
Są ludzie na SO, którzy nie lubią zmiennych tabeli, ale lubię je, ponieważ są zmaterializowane i szybsze w tworzeniu niż #temp. Są chwile, kiedy optymalizator zapytań radzi sobie lepiej z wartością #temp w porównaniu ze zmienną tabelową.
Możliwość utworzenia PK na zmiennej #temp lub tabeli daje optymalizatorowi zapytania więcej informacji niż CTE (ponieważ nie można zadeklarować PK na CTE).
źródło
Myślę, że tylko 2 rzeczy sprawiają, że ZAWSZE lepiej jest używać tabeli # Temp niż CTE:
Nie można umieścić klucza podstawowego na CTE, więc dane, do których ma dostęp CTE, będą musiały przejść przez każdy z indeksów w tabelach CTE, a nie tylko uzyskać dostęp do PK lub indeksu w tabeli tymczasowej.
Ponieważ nie można dodawać ograniczeń, indeksów i kluczy podstawowych do CTE, są one bardziej podatne na wkradanie się błędów i złe dane.
-ponad wczoraj
Oto przykład, w którym ograniczenia #table mogą zapobiegać złym danym, co nie ma miejsca w CTE
źródło
ALWAYS
jest trochę za daleko, ale dziękuję za odpowiedź. Jeśli chodzi o czytelność, użycie CTE może być dobrą rzeczą.CHECK
Ograniczenie odnoszące się do wielu wierszy / tabel jest nie dozwolony). Czy możesz opublikować przykład, w którym CTE wykazuje błąd, którego nie ma odpowiednik tabeli tymczasowej?