Preskočiť na obsah
Návod

Table variable vs. #temp tabuľka – odhady a deferred compilation (2019+)

Prečo table variable odhaduje 1 riadok, čo zmenila table variable deferred compilation v SQL Server 2019 (compat 150), kedy použiť #temp tabuľku a OPTION (RECOMPILE).

3 min čítania 3 kroky 1 obrázok SQL Server 2016+
> [!TIP]
> Recept z [kuchárky exekučných plánov](script.php?id=64&s=exekucne-plany-kucharka-zacni-tu). Ukážky bežia v testovacej databáze [PlanLab](script.php?id=65&s=planlab-testovacia-databaza-pre-recepty-exekucnych-planov) – nikdy ich nespúšťaj na produkcii.

## Ako to vyzerá v pláne

![Odhady pre table variable a #temp](uploads/2026/11/plan-p3.svg "Table variable bez štatistík vs. #temp tabuľka")

Pri table variable (`@t`) vidíš sken s *Estimated Number of Rows* = **1** (pred SQL Server 2019) a skutočnosť v tisíckach. Nasleduje typicky Nested Loops so 50 000 vykonaniami.

## Čo to znamená

**Table variable** (`DECLARE @t TABLE`) nemá štatistiky a dotaz s ňou sa kompiluje skôr, než sa naplní. Optimalizátor preto do SQL Server 2017 predpokladá **1 riadok**. **#temp tabuľka** je obyčajná tabuľka v tempdb – má štatistiky, odhad je presný a pri veľkej zmene obsahu sa dotaz rekompiluje.

### Do hĺbky

- **Table variable deferred compilation** (SQL Server 2019+, compat 150): príkaz s table variable sa skompiluje až pri prvom vykonaní, takže použije **skutočný počet riadkov** z prvého behu. Stále však nepozná **rozdelenie hodnôt** (štatistiky stĺpcov) a ďalšie spustenia použijú ten istý plán.
- `OPTION (RECOMPILE)` na príkaze s table variable dá optimalizátoru aktuálny počet riadkov aj v starších verziách.
- Table variable nespôsobuje rekompilácie a pri malých počtoch riadkov (desiatky) je úplne v poriadku.
- Modifikácia table variable (INSERT … SELECT do @t) nemôže bežať paralelne; čítanie z nej áno.
- #temp tabuľka sa dá indexovať aj po vytvorení a má štatistiky – vhodná pre medzivýsledky so stovkami a viac riadkov.

## Kedy je to v poriadku / kedy problém

| V poriadku | Problém |
|---|---|
| desiatky riadkov, jednoduché použitie | tisíce riadkov a spojenie s veľkou tabuľkou |
| 2019+ a stabilný počet riadkov | počet riadkov sa medzi volaniami veľmi mení |
| #temp pre veľké medzivýsledky | Nested Loops s tisíckami vykonaní za table variable |

## Ako si to vyskúšať

```sql
USE PlanLab;
ALTER DATABASE PlanLab SET COMPATIBILITY_LEVEL = 140;   -- správanie pred 2019
GO
DECLARE @t TABLE (OrderID int PRIMARY KEY);
INSERT @t SELECT TOP (50000) OrderID FROM dbo.Orders WHERE CustomerID = 1;
SELECT COUNT(*) FROM @t AS t JOIN dbo.OrderLines AS l ON l.OrderID = t.OrderID;   -- odhad 1
GO
CREATE TABLE #t (OrderID int PRIMARY KEY);
INSERT #t SELECT TOP (50000) OrderID FROM dbo.Orders WHERE CustomerID = 1;
SELECT COUNT(*) FROM #t AS t JOIN dbo.OrderLines AS l ON l.OrderID = t.OrderID;   -- odhad 50 000
DROP TABLE #t;
GO
ALTER DATABASE PlanLab SET COMPATIBILITY_LEVEL = 150;   -- 2019+: deferred compilation (ak to server podporuje)
GO
DECLARE @t TABLE (OrderID int PRIMARY KEY);
INSERT @t SELECT TOP (50000) OrderID FROM dbo.Orders WHERE CustomerID = 1;
SELECT COUNT(*) FROM @t AS t JOIN dbo.OrderLines AS l ON l.OrderID = t.OrderID;   -- odhad 50 000
```

Spusti s **Include Actual Execution Plan** (Ctrl+M) a porovnaj odhad pri skene `@t` / `#t` a zvolené spojenie. Compat level potom vráť na pôvodnú hodnotu.

## Čo s tým

1. Medzivýsledky so stovkami a viac riadkov ukladaj do **#temp** tabuliek.
2. Ak musí ostať table variable: `OPTION (RECOMPILE)` na príkaze, ktorý ju číta, alebo SQL Server 2019+ s compat 150.
3. Na 2019+ pri veľmi premenlivom počte riadkov pomôže tiež RECOMPILE – deferred compilation platí len pre prvé spustenie.

## Súvisiace

- [Zlé odhady riadkov](script.php?id=84&s=zle-odhady-riadkov-odhad-vs-skutocnost-a-statistiky)
- [Nested Loops](script.php?id=71&s=nested-loops-vnorene-cykly-outer-a-inner-vstup)
- [Funkcie v pláne (MSTVF)](script.php?id=83&s=funkcie-v-plane-scalar-udf-inlining-2019-a-table-valued-funkcie)
- [Kto spotrebúva tempdb](script.php?id=20&s=kto-spotrebuva-tempdb)

## Zdroje

- [Microsoft Learn – table (Transact-SQL)](https://learn.microsoft.com/sql/t-sql/data-types/table-transact-sql)
- [Microsoft Learn – Intelligent query processing details](https://learn.microsoft.com/sql/relational-databases/performance/intelligent-query-processing-details)
- [Microsoft Learn – Intelligent query processing](https://learn.microsoft.com/sql/relational-databases/performance/intelligent-query-processing)
- [Paul White – SQLkiwi (články o optimalizátore a operátoroch)](https://www.sql.kiwi/)

_Texty sú vlastné, tvrdenia overené proti uvedeným zdrojom (11/2026). T-SQL je staticky skontrolovaný, nie spustený na živom serveri – vyskúšaj ho najprv v PlanLab._