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ł
#temporary
stół. 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ąUNIQUE
lubPRIMARY KEY
ograniczenie. 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
#temporary
stół. To obsługujeTRUNCATE
(co jest bardziej wydajne niżDELETE
dla dużych tabel) i dodatkowo kolejne wstawki poTRUNCATE
mogą mieć lepszą wydajność niż te poDELETE
jak 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
#temporary
stół. 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
SELECT
nastę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
#temp
tabela 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ęciutempdb
dziennik 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
#temporary
tabele. Bob Ward wskazuje w swoimtempdb
prezentacja, ż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