📁 Temporäre Tabellen & Tabellenvariablen in T‑SQL
Grundlagen: Wozu dienen temporäre Objekte?
ÜBERBLICK-- Vereinfachtes Beispiel: Mehrere Abfragen mit einer temporären Struktur verknüpfen
CREATE TABLE #Zwischenergebnis (ID INT, Name NVARCHAR(100));
INSERT INTO #Zwischenergebnis VALUES (1, 'Datenbank'), (2, 'Entwicklung');
SELECT * FROM #Zwischenergebnis;
-- Die Tabelle existiert nur während der aktuellen Sitzung
Lokale temporäre Tabellen (#temp)
SITZUNGSGEBUNDEN-- Schritt 1: Lokale Temp‑Tabelle anlegen und füllen
CREATE TABLE #KundenBestellungen (
KundenID INT,
Bestellanzahl INT
);
INSERT INTO #KundenBestellungen
SELECT KundenID, COUNT(BestellID)
FROM Bestellungen
GROUP BY KundenID;
-- Schritt 2: Mit anderen Tabellen verknüpfen
SELECT k.Name, kb.Bestellanzahl
FROM Kunden k
INNER JOIN #KundenBestellungen kb ON k.KundenID = kb.KundenID;
-- Sauberes Aufräumen (optional, da automatisch)
DROP TABLE #KundenBestellungen;
Globale temporäre Tabellen (##temp)
ÜBER SITZUNGEN HINAUS-- Eine Sitzung erstellt die globale Tabelle
CREATE TABLE ##GlobaleLogTabelle (
EreignisID INT,
Zeitstempel DATETIME DEFAULT GETDATE()
);
INSERT INTO ##GlobaleLogTabelle (EreignisID) VALUES (1), (2);
-- Eine andere Sitzung kann auf die Tabelle zugreifen
SELECT * FROM ##GlobaleLogTabelle;
-- Explizites Löschen beendet die Lebensdauer sofort
DROP TABLE ##GlobaleLogTabelle;
Tabellenvariablen (@table)
SCOPE · BATCHDECLARE @MeineTabelle TABLE (
ArtikelID INT PRIMARY KEY,
Menge INT,
Status NVARCHAR(20)
);
INSERT INTO @MeineTabelle VALUES (101, 5, 'offen'), (102, 3, 'versendet');
SELECT * FROM @MeineTabelle;
-- Nach Ende des Batches ist die Variable automatisch aufgeräumt
Vergleich: #temp vs. ##temp vs. @table
PERFORMANCE & MERKMALE/* --- 1. Indizierung und Statistiken --- */
-- Temporäre Tabelle: volle Indexunterstützung + Statistiken
CREATE TABLE #BeispielTemp (ID INT PRIMARY KEY, Wert NVARCHAR(100));
CREATE INDEX IX_Wert ON #BeispielTemp(Wert);
-- Tabellenvariable: nur PRIMARY KEY / UNIQUE (in neueren Versionen auch Non‑Clustered)
DECLARE @BeispielVar TABLE (ID INT PRIMARY KEY, Wert NVARCHAR(100));
/* --- 2. Transaktionsverhalten --- */
BEGIN TRAN;
INSERT INTO #BeispielTemp VALUES (1, 'Temp');
INSERT INTO @BeispielVar VALUES (1, 'Var');
ROLLBACK;
-- Ergebnis: #BeispielTemp wird zurückgesetzt, @BeispielVar bleibt gefüllt.
/* --- 3. Geltungsbereich und Sichtbarkeit --- */
-- #temp: nur aktuelle Sitzung (einschließlich verschachtelter SPs)
-- ##temp: alle Sitzungen (bis letzter Verweis verschwindet)
-- @table: nur aktueller Batch / aktuelle Routine
- Lokale Temp‑Tabelle (#): Volle Index- und Statistikunterstützung, sichtbar in der gesamten Sitzung, ideal für mittlere bis große Datenmengen oder komplexe Abfragen.
- Globale Temp‑Tabelle (##): Wie #, aber für mehrere Sitzungen sichtbar – nützlich für abteilungsübergreifende Arbeitsflächen.
- Tabellenvariable (@table): Sehr geringer Overhead, keine Statistik, kein Transaktions‑Rollback – perfekt für kleine Lookuptabellen oder temporäre Parameter in Funktionen.
Best Practices & häufige Fallstricke
PRAXISTIPPS-- ✅ Vor der Erstellung eine vorhandene Temp‑Tabelle löschen (robust)
IF OBJECT_ID('tempdb..#Sicherheit', 'U') IS NOT NULL
DROP TABLE #Sicherheit;
CREATE TABLE #Sicherheit (ID INT);
-- ❌ Vermeiden: Tabellenvariable in dynamischem SQL (außerhalb des Scopes)
DECLARE @sql NVARCHAR(MAX) = 'SELECT * FROM @MeineTabelle';
EXEC sp_executesql @sql; -- Fehler: @MeineTabelle nicht bekannt
-- ✅ Aber: Temporäre Tabelle funktioniert im dynamischen SQL
EXEC ('CREATE TABLE #TempDyn (ID INT); INSERT INTO #TempDyn VALUES (1); SELECT * FROM #TempDyn;');
-- 💡 Index auf Tabellenvariablen explizit vorgeben (ab SQL Server 2014)
DECLARE @Optimiert TABLE (
Id INT PRIMARY KEY,
Suchwert NVARCHAR(100) INDEX IX_Suchwert NONCLUSTERED
);
- Singleton-Lookups oder sehr kleine Ergebnismengen: Tabellenvariable
- Permanente Indexierung, große Datenmengen oder parallele Pläne gewünscht: Lokale Temp‑Tabelle
- Datenaustausch zwischen verschiedenen Sitzungen: Globale Temp‑Tabelle (##temp)
- Fehlerprotokollierung, die ein ROLLBACK überstehen muss: Tabellenvariable (bleibt bei Rücksetzung erhalten)
- Verwenden Sie SELECT ... INTO #temp, um schnell eine Temp‑Tabelle aus einem Abfrageergebnis zu erzeugen.
- Beachten Sie, dass lokale Temp‑Tabellen in der tempdb ähnlich viel Logging verursachen wie normale Tabellen, während Tabellenvariablen dies minimieren.
- Der Geltungsbereich einer Tabellenvariablen endet mit dem Batch – sie ist nicht in verschachtelten gespeicherten Prozeduren sichtbar.
- Setzen Sie primäre und ggf. nicht gruppierte Indizes auf Tabellenvariablen, um Suchoperationen zu beschleunigen.
- Nutzen Sie die tempdb‑Leistungsindikatoren, um Engpässe durch übermäßige Temp‑Tabellen‑Aktivität zu erkennen.
📄 Spickzettel: Syntax auf einen Blick
-- Lokale temporäre Tabelle (existiert nur in der aktuellen Sitzung)
CREATE TABLE #LokalTemp (Spalte1 INT, Spalte2 NVARCHAR(50));
-- einfache Befüllung
INSERT INTO #LokalTemp SELECT ID, Name FROM Quelle;
-- Globale temporäre Tabelle (sichtbar für alle Sitzungen)
CREATE TABLE ##GlobalTemp (ID INT PRIMARY KEY, Wert DECIMAL(10,2));
-- Tabellenvariable (nur im aktuellen Batch gültig)
DECLARE @TabVar TABLE (ID INT PRIMARY KEY, Beschreibung NVARCHAR(200));
INSERT INTO @TabVar VALUES (1, 'Beispiel');
SELECT * FROM @TabVar;
✅ Fazit – Temporäre Tabellen und Tabellenvariablen sind unverzichtbare Werkzeuge für saubere, mehrstufige T‑SQL‑Logik. Mit dem Wissen über Lebensdauer, Indizierung und Performanceeigenschaften können Sie die passende Struktur für Ihre Arbeitslast auswählen.