Jaka jest różnica między CTE a tabelą temperatur?


174

Jaka jest różnica między Common Table Expression (CTE) a tabelą tymczasową? A kiedy powinienem używać jednego na drugim?

CTE

WITH cte (Column1, Column2, Column3)
AS
(
    SELECT Column1, Column2, Column3
    FROM SomeTable
)

SELECT * FROM cte

Tabela temperatur

SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable

SELECT * FROM #tmpTable


Odpowiedzi:


200

Jest to dość ogólne, ale dam ci tak ogólną odpowiedź, jak tylko potrafię.

CTE ...

  • Są nieindeksowalne (ale mogą korzystać z istniejących indeksów na obiektach odniesienia)
  • Nie może mieć ograniczeń
  • Są zasadniczo jednorazowe VIEWs
  • Trwać tylko do momentu uruchomienia następnego zapytania
  • Może być rekurencyjny
  • Nie posiadaj dedykowanych statystyk (polegaj na statystykach na obiektach bazowych)

# Tabele temperatur ...

  • Są prawdziwymi zmaterializowanymi tabelami, które istnieją w tempdb
  • Może być indeksowany
  • Może mieć ograniczenia
  • Trwaj do końca obecnego POŁĄCZENIA
  • Mogą się odnosić do innych zapytań lub podprocedur
  • Mają dedykowane statystyki generowane przez silnik

Jeśli chodzi o to, kiedy z nich korzystać, mają one bardzo różne przypadki użycia. Jeśli będziesz mieć bardzo duży zestaw wyników lub będziesz musiał odwoływać się do niego więcej niż jeden raz, umieść go w #temptabeli. Jeśli wymaga rekurencji, jest jednorazowego użytku lub po prostu upraszcza coś logicznie, CTEpreferowane jest a .

Ponadto, CTEpowinny nigdy być wykorzystywane do realizacji . Prawie nigdy nie przyspieszysz korzystania z CTE, ponieważ znowu jest to tylko widok jednorazowy. Możesz robić z nimi porządne rzeczy, ale przyspieszenie zapytania nie jest tak naprawdę jedną z nich.


przyspieszenie dużego MERGE za pomocą CTE to rzecz
AgentFire

1
Przyspieszanie wielu zapytań za pomocą CTE jest również rzeczą, ponieważ dzięki CTE możesz dodać własną wiedzę biznesową, aby przewyższyć optymalizator zapytań. Na przykład możesz wybrać część 1 CTE do wyboru z tabel, w których wiesz, że wynikowe wiersze będą bardzo małe. W ramach tego samego zapytania możesz dołączyć ten niewielki zestaw wyników do jakiegoś większego zestawu wyników i całkowicie ominąć problemy spowodowane przez nieaktualne statystyki itp. Aby to zrobić, musisz dodać wskazówki do zapytania, aby wymusić kolejność. Działa, poprawia wydajność.
Dave Hilditch

„nigdy nie należy wykorzystywać do działania” jest szerokim i nieco subiektywnym stwierdzeniem, chociaż rozumiem twój punkt widzenia. Jednak, oprócz innych komentarzy, może wystąpić inny potencjalny wzrost wydajności przy użyciu CTE przy przełączaniu na rekurencyjną CTE z innej formy rekurencji, takiej jak rekurencyjne wywołania procedur lub kursor.
JD

29

EDYTOWAĆ:

Zobacz komentarze Martina poniżej:

CTE nie jest zmaterializowany jako tabela w pamięci. To tylko sposób na zawarcie definicji zapytania. W przypadku PO będzie on wstawiony i to samo, co po prostu robienie SELECT Column1, Column2, Column3 FROM SomeTable. Przez większość czasu nie zostają zmaterializowane z góry, dlatego nie zwraca żadnych wierszy WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, sprawdź także plany wykonania. Chociaż czasami można zhakować plan, aby uzyskać szpulę. Istnieje element połączeniowy z prośbą o podpowiedź. - Martin Smith 15 lutego 12 'o 17:08


Oryginalna odpowiedź

CTE

Przeczytaj więcej na MSDN

CTE tworzy tabelę używaną w pamięci, ale jest poprawna tylko dla określonego zapytania po niej. Podczas korzystania z rekurencji może to być efektywna struktura.

Możesz również rozważyć użycie zmiennej tabeli. Jest to używane, ponieważ używana jest tabela tymczasowa i może być używana wiele razy, bez potrzeby ponownego zmaterializowania dla każdego połączenia. Ponadto, jeśli musisz teraz zachować kilka rekordów, dodaj kilka kolejnych rekordów po kolejnym wyborze, dodaj jeszcze kilka rekordów po kolejnej operacji, a następnie zwróć tylko garść rekordów, to może być przydatna struktura, ponieważ nie trzeba go upuszczać po wykonaniu. Głównie tylko cukier syntaktyczny. Jeśli jednak utrzymasz niską liczbę wierszy, nigdy nie pojawi się ona na dysku. Zobacz Jaka jest różnica między tabelą tymczasową a zmienną tabelową w programie SQL Server? po więcej szczegółów.

Tabela temperatur

Przeczytaj więcej na MSDN - Przewiń w dół o około 40%

Tabela tymczasowa to dosłownie tabela utworzona na dysku, tylko w określonej bazie danych, o której wszyscy wiedzą, że można ją usunąć. Dobry deweloper jest odpowiedzialny za zniszczenie tych tabel, gdy nie są już potrzebne, ale DBA może je również wyczyścić.

Stoły tymczasowe występują w dwóch odmianach: lokalnej i globalnej. W odniesieniu do MS Sql Server używasz #tableNameoznaczenia lokalnego i ##tableNameglobalnego (zwróć uwagę na użycie pojedynczego lub podwójnego # jako cechy identyfikującej).

Zauważ, że w przypadku tabel tymczasowych, w przeciwieństwie do zmiennych tabel lub CTE, możesz zastosować indeksy i tym podobne, ponieważ są to legalne tabele w normalnym znaczeniu tego słowa.


Zasadniczo korzystałbym z tabel tymczasowych dla dłuższych lub większych zapytań oraz zmiennych CTE lub zmiennych tabel, gdybym miał już mały zestaw danych i chciałem po prostu szybko napisać trochę kodu dla czegoś małego. Doświadczenie i porady innych wskazują, że powinieneś używać CTE tam, gdzie zwracana jest niewielka liczba wierszy. Jeśli masz dużą liczbę, prawdopodobnie skorzystasz z możliwości indeksowania w tabeli tymczasowej.


11
CTE nie jest zmaterializowany jako tabela w pamięci. To tylko sposób na zawarcie definicji zapytania. W przypadku PO będzie on wstawiony i to samo, co po prostuSELECT Column1, Column2, Column3 FROM SomeTable
Martin Smith

4
Przez większość czasu nie zostają zmaterializowane z góry, dlatego nie zwraca żadnych wierszy WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, sprawdź także plany wykonania. Chociaż czasami można zhakować plan, aby uzyskać szpulę. Istnieje element połączeniowy z prośbą o podpowiedź.
Martin Smith

16

Zaakceptowane odpowiedź tu mówi „CTE nigdy nie powinny być wykorzystywane do realizacji” - ale które mogłyby wprowadzać w błąd. W kontekście tabel CTE kontra tabele tymczasowe właśnie skończyłem usuwać zbędne śmieci z zestawu przechowywanych proc, ponieważ niektórzy doofus musieli myśleć, że użycie tabel tymczasowych jest niewielkie lub wcale. Wrzuciłem wiele do CTE, z wyjątkiem tych, które zgodnie z prawem miały być ponownie wykorzystane podczas całego procesu. Zyskałem około 20% wydajności według wszystkich wskaźników. Następnie przystąpiłem do usuwania wszystkich kursorów, które próbowały zaimplementować przetwarzanie rekurencyjne. To tam widziałem największy zysk. Ostatecznie zmniejszyłem czasy reakcji dziesięciokrotnie.

CTE i tabele tymczasowe mają bardzo różne przypadki użycia. Chciałbym tylko podkreślić, że chociaż nie jest to panaceum, zrozumienie i poprawne użycie CTE może prowadzić do naprawdę naprawdę doskonałej poprawy zarówno jakości / obsługi kodu, jak i szybkości. Odkąd je opanowałem, uważam tabele tymczasowe i kursory za wielkie zło przetwarzania SQL. Mogę teraz sobie poradzić ze zmiennymi tabel i współczynnikami CTE dla prawie wszystkiego teraz. Mój kod jest czystszy i szybszy.


A teraz bądźmy sprawiedliwi - kursory są wielkim złem; tabele tymczasowe są w najgorszym przypadku mniejszym złem. :-) Naprawdę niesprawiedliwe jest umieszczanie ich na tym samym poziomie, co sam siebie widziałeś.
RDFozz

@RDFozz dobrze, piekło ma 9 kręgów, jak wszyscy wiemy . Ustawmy tabele tymczasowe na 2, a kursory na ... 7? ;)
ypercubeᵀᴹ

1
Wiesz, czym jest „wielkie zło” w programowaniu? Kiedy ludzie mówią, że dana technika jest zła. Jest miejsce dla kursorów. Mogą przewyższyć inne techniki w niektórych scenariuszach. Nie ma tu zła - musisz nauczyć się korzystać z odpowiedniego narzędzia do pracy. Mierz to, co robisz i nie wierz w szum, że CTE, tabele temp lub kursory są złe. Zmierz - bo prawda zależy od scenariusza.
Dave Hilditch

@DaveHilditch jest to uczciwy komentarz, ale jest to również uczciwy komentarz, aby stwierdzić, że w bardzo, bardzo wielu sytuacjach kursory nie są właściwym rozwiązaniem, więc jest praktycznym uogólnieniem, aby mieć je również w ostateczności.
Mel Padden

1
Z mojego doświadczenia, KURSOR sam w sobie nie jest zły. KURSORY są często „niewłaściwie” używane przez programistów, ponieważ w większości języków programowania musisz myśleć iteracyjnie, w przeciwieństwie do SQL, w którym najczęściej musisz myśleć partiami. Wiem, że jest to częsty błąd w moim miejscu pracy, w którym deweloperzy po prostu nie „widzą” wyjścia z problemu innego niż CURSOR, dlatego też dobry DBA przydaje się uczyć i poprawiać je. @DaveHilditch ma całkowitą rację: wystarczy odpowiednie narzędzie do właściwej pracy.
Philippe

14

CTE może być wywoływany wielokrotnie w zapytaniu i jest oceniany za każdym razem, gdy się do niego odwołuje - proces ten może być rekurencyjny. Jeśli zostanie tylko raz odesłany, zachowuje się podobnie do zapytania podrzędnego, chociaż parametry CTE można sparametryzować.

Tabela tymczasowa jest utrwalana fizycznie i może być indeksowana. W praktyce optymalizator zapytań może również zachowywać wyniki pośrednich połączeń lub zapytań za scenami, na przykład w operacjach buforowania, więc nie jest prawdą, że wyniki CTE nigdy nie są utrwalane na dysku.

Z drugiej strony zmienne tabeli IIRC są zawsze strukturami w pamięci.


4
CTE można sparametryzować? W jaki sposób? Ponadto zmienne tabeli nie zawsze są strukturami w pamięci. Zobacz doskonałą odpowiedź Martina na powiązane pytanie.
Paul White

11

Tabela temp jest prawdziwym obiektem w tempdb, ale cte jest tylko rodzajem otulenia złożonego zapytania w celu uproszczenia składni organizacji rekurencji w jednym kroku.


8

Podstawowym powodem korzystania z CTE jest dostęp do funkcji okien, takich jak row_number()i wiele innych.

Oznacza to, że możesz robić rzeczy takie jak uzyskanie pierwszego lub ostatniego wiersza na grupę BARDZO BARDZO bardzo szybko i wydajnie - bardziej efektywnie niż inne środki w większości praktycznych przypadków .

with reallyfastcte as (
select *, 
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;

Możesz uruchomić zapytanie podobne do powyższego, używając skorelowanego podzapytania lub zapytania częściowego, ale CTE będzie szybsze w prawie wszystkich scenariuszach.

Ponadto CTE mogą naprawdę uprościć kod. Może to prowadzić do wzrostu wydajności, ponieważ lepiej rozumiesz zapytanie i możesz wprowadzić więcej logiki biznesowej, aby zoptymalizować optymalizator.

Dodatkowo, CTE mogą zwiększyć wydajność, jeśli rozumiesz logikę biznesową i wiesz, które części zapytania powinny być uruchamiane jako pierwsze - zazwyczaj stawiaj najpierw najbardziej selektywne zapytania, które prowadzą do zestawów wyników, które mogą korzystać z indeksu przy następnym łączeniu i dodaj option(force order)zapytanie Wskazówka

Wreszcie, CTE nie używają domyślnie tempdb, więc zmniejszasz rywalizację o to wąskie gardło poprzez ich użycie.

Tabel tymczasowych należy używać, jeśli trzeba wielokrotnie wysyłać zapytania do danych, lub alternatywnie, jeśli mierzy się zapytania i odkrywa się je, wstawiając do tabeli tymczasowej, a następnie dodając indeks poprawiający wydajność.


wszystkie dobre punkty ... +1
Mel Padden

6

Wydaje się, że jest tu trochę negatywności w stosunku do CTE.

Rozumiem, że CTE jest taki, że jest to rodzaj doraźnego poglądu. SQL jest zarówno językiem deklaratywnym, jak i opartym na zestawie. CTE to świetny sposób na zadeklarowanie zestawu! Brak możliwości indeksowania CTE jest w rzeczywistości dobrą rzeczą, ponieważ nie jest to konieczne! To naprawdę rodzaj cukru syntaktycznego, który ułatwia odczyt / zapis zapytania. Każdy porządny optymalizator opracuje najlepszy plan dostępu, korzystając z indeksów na bazowych tabelach. Oznacza to, że możesz skutecznie przyspieszyć zapytanie CTE, postępując zgodnie ze wskazówkami dotyczącymi indeksu w bazowych tabelach.

Również dlatego, że zdefiniowałeś zestaw jako CTE, nie oznacza to, że wszystkie wiersze w zestawie muszą zostać przetworzone. W zależności od zapytania optymalizator może przetworzyć „wystarczającą” liczbę wierszy, aby spełnić zapytanie. Może potrzebujesz tylko pierwszych 20 lub więcej na ekranie. Jeśli zbudowałeś tabelę tymczasową, to naprawdę musisz czytać / pisać wszystkie te wiersze!

Na tej podstawie powiedziałbym, że CTE są świetną funkcją SQL i mogą być używane wszędzie tam, gdzie ułatwiają odczytanie zapytania. Myślałem tylko o tabeli tymczasowej dla procesu wsadowego, który naprawdę musiałby przetworzyć każdy rekord. Nawet wtedy nie jest to zalecane, ponieważ w tabeli tymczasowej bazy danych jest znacznie trudniej pomóc w buforowaniu i indeksach. Lepiej mieć stały stół z polem PK unikatowym dla Twojej transakcji.

Muszę przyznać, że moje doświadczenie dotyczy głównie DB2, więc zakładam, że CTE działa w podobny sposób w obu produktach. Z chęcią stanę się poprawiony, jeśli CTE są w jakiś sposób gorsze na serwerze SQL. ;)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.