Twoje pytanie pokazuje, że uległeś niektórym typowym nieporozumieniom dotyczącym zmiennych tabel i tabel tymczasowych.
Napisałem dość obszerną odpowiedź na stronie DBA, patrząc na różnice między dwoma typami obiektów. To również odnosi się do twojego pytania o dysk a pamięć (nie zauważyłem żadnej znaczącej różnicy w zachowaniu między tymi dwoma).
Jeśli chodzi o pytanie w tytule, ale kiedy użyć zmiennej tabeli w porównaniu z lokalną tabelą tymczasową, nie zawsze masz wybór. Na przykład w funkcjach można używać tylko zmiennej tabeli, a jeśli potrzebujesz pisać do tabeli w zakresie podrzędnym, to tylko #temp table zrobi to (parametry wyceniane w tabeli umożliwiają dostęp tylko do odczytu).
Jeśli masz wybór, poniżej znajdziesz kilka sugestii (chociaż najbardziej niezawodną metodą jest po prostu przetestowanie obu przy określonym obciążeniu).
-
Jeśli potrzebujesz indeksu, którego nie można utworzyć na zmiennej tabeli, będziesz oczywiście potrzebował
#temporarystół. Szczegóły tego są jednak zależne od wersji. W przypadku SQL Server 2012 i starszych jedynymi indeksami, które można było utworzyć na zmiennych tabeli, były te niejawnie utworzone za pomocąUNIQUElubPRIMARY KEYograniczenie. SQL Server 2014 wprowadził składnię indeksu wbudowanego dla podzbioru opcji dostępnych wCREATE INDEX. Zostało to rozszerzone od tego czasu, aby umożliwić filtrowane warunki indeksowania. Indeksy zINCLUDE-d kolumny lub indeksy magazynu kolumn nadal nie są jednak możliwe do tworzenia na zmiennych tabeli. -
Jeśli będziesz wielokrotnie dodawać i usuwać dużą liczbę wierszy z tabeli, użyj
#temporarystół. To obsługujeTRUNCATE(co jest bardziej wydajne niżDELETEdla dużych tabel) i dodatkowo kolejne wstawki poTRUNCATEmogą mieć lepszą wydajność niż te poDELETEjak pokazano tutaj. - Jeśli będziesz usuwać lub aktualizować dużą liczbę wierszy, tabela tymczasowa może działać znacznie lepiej niż zmienna tabeli — jeśli jest w stanie korzystać z udostępniania zestawów wierszy (patrz przykład „Efekty udostępniania zestawów wierszy” poniżej) .
- Jeśli optymalny plan wykorzystujący tabelę będzie się różnić w zależności od danych, użyj
#temporarystół. To wspiera tworzenie statystyk, które pozwalają na dynamiczną rekompilację planu zgodnie z danymi (chociaż w przypadku buforowanych tabel tymczasowych w procedurach składowanych zachowanie rekompilacji należy rozumieć oddzielnie). - Jeśli optymalny plan dla zapytania używającego tabeli prawdopodobnie nigdy się nie zmieni, możesz rozważyć zmienną tabeli, aby pominąć obciążenie związane z tworzeniem statystyk i ponowną kompilacją (prawdopodobnie wymagałoby to wskazówek, aby naprawić żądany plan).
- Jeśli źródło danych wstawionych do tabeli pochodzi z potencjalnie drogiego
SELECTnastępnie rozważ, że użycie zmiennej tabeli zablokuje możliwość korzystania z planu równoległego. - Jeśli potrzebujesz danych w tabeli, aby przetrwać wycofanie transakcji użytkownika zewnętrznego, użyj zmiennej tabeli. Możliwym przypadkiem użycia tego może być rejestrowanie postępu różnych kroków w długiej partii SQL.
- Gdy używasz
#temptabela wewnątrz transakcji użytkownika może być utrzymywana dłużej niż w przypadku zmiennych tabeli (potencjalnie do końca transakcji vs końca instrukcji w zależności od typu blokady i poziomu izolacji), a także może zapobiec obcięciutempdbdziennik transakcji do zakończenia transakcji użytkownika. Może to więc sprzyjać używaniu zmiennych tabeli. - W ramach przechowywanych procedur można buforować zarówno zmienne tabel, jak i tabele tymczasowe. Obsługa metadanych dla buforowanych zmiennych tabeli jest mniejsza niż dla
#temporarytabele. Bob Ward wskazuje w swoimtempdbprezentacja, że może to spowodować dodatkową rywalizację o tabele systemowe w warunkach wysokiej współbieżności. Dodatkowo, gdy mamy do czynienia z małymi ilościami danych, może to mieć wymierną różnicę w wydajności.
Skutki udostępniania zestawu wierszy
DECLARE @T TABLE(id INT PRIMARY KEY, Flag BIT);
CREATE TABLE #T (id INT PRIMARY KEY, Flag BIT);
INSERT INTO @T
output inserted.* into #T
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID), 0
FROM master..spt_values v1, master..spt_values v2
SET STATISTICS TIME ON
/*CPU time = 7016 ms, elapsed time = 7860 ms.*/
UPDATE @T SET Flag=1;
/*CPU time = 6234 ms, elapsed time = 7236 ms.*/
DELETE FROM @T
/* CPU time = 828 ms, elapsed time = 1120 ms.*/
UPDATE #T SET Flag=1;
/*CPU time = 672 ms, elapsed time = 980 ms.*/
DELETE FROM #T
DROP TABLE #T