> [!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

V SSMS: **Segment** a **Sequence Project** (ROW_NUMBER, RANK, DENSE_RANK, NTILE), pri agregáciách s rámcom (`SUM() OVER (ORDER BY …)`) navyše **Window Spool** a **Stream Aggregate**. V batch mode jediný operátor **Window Aggregate**. Pred nimi často **Sort**.
## Čo to znamená
Window funkcie potrebujú riadky **zoradené podľa PARTITION BY a ORDER BY**. **Segment** označí hranice skupín (kde sa mení hodnota PARTITION BY), **Sequence Project** prejde riadky skupiny a pridelí poradie. Pri bežiacich súčtoch si **Window Spool** drží riadky aktuálneho rámca a Stream Aggregate z nich počíta.
### Do hĺbky
- **Sort** pred Segmentom je najdrahšia časť. Ušetrí ho index v poradí **P**artition, **O**rder, s **C**overing stĺpcami (tzv. *POC index*).
- **Predvolený rámec**: keď napíšeš `ORDER BY` bez rámca, platí `RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`. Pre row mode to znamená Window Spool s **pracovnou tabuľkou na disku** (tempdb, v STATISTICS IO veľké čísla pri *Worktable*). `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` používa spool v pamäti a je výrazne rýchlejší. Výsledok sa líši len pri duplicitných hodnotách v ORDER BY.
- **Window Aggregate** (batch mode, od SQL Server 2016 s columnstore v dotaze, od 2019 aj nad rowstore pri compat 150) nepotrebuje Window Spool ani pracovnú tabuľku.
- LAG / LEAD / FIRST_VALUE / LAST_VALUE sú v row mode tiež riešené cez Window Spool s rámcom.
- ROW_NUMBER v poddotaze s filtrom `WHERE rn = 1` je bežný spôsob „posledný riadok na skupinu“ – s POC indexom je to Segment + Sequence Project bez Sort.
## Kedy je to v poriadku / kedy problém
| V poriadku | Problém |
|---|---|
| Segment + Sequence Project bez Sort (POC index) | Sort miliónov riadkov so spillom |
| Window Spool s rámcom ROWS (v pamäti) | Window Spool s RANGE – Worktable s miliónmi čítaní |
| Window Aggregate v batch mode | – |
## Ako si to vyskúšať
```sql
USE PlanLab;
SET STATISTICS IO ON;
-- 1) ROW_NUMBER: Sort + Segment + Sequence Project
SELECT CustomerID, OrderID, OrderDate,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) AS rn
FROM dbo.Orders
WHERE CustomerID <= 2000;
-- 2) Bežiaci súčet s predvoleným rámcom (RANGE) → Window Spool na disku
SELECT OrderID, SUM(Amount) OVER (ORDER BY OrderID) AS priebezne
FROM dbo.Orders WHERE OrderID <= 100000;
-- 3) Rovnaký súčet s ROWS → spool v pamäti (porovnaj Worktable v Messages)
SELECT OrderID, SUM(Amount) OVER (ORDER BY OrderID ROWS UNBOUNDED PRECEDING) AS priebezne
FROM dbo.Orders WHERE OrderID <= 100000;
-- 4) POC index: Sort zmizne
CREATE INDEX IX_Lab_Orders_POC ON dbo.Orders (CustomerID, OrderDate DESC);
SELECT CustomerID, OrderID, OrderDate,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) AS rn
FROM dbo.Orders
WHERE CustomerID <= 2000;
DROP INDEX IX_Lab_Orders_POC ON dbo.Orders;
```
Spusti s **Include Actual Execution Plan** (Ctrl+M) a porovnaj v *Messages* riadky *Worktable* pri bodoch 2 a 3. (V compat level 150+ na Enterprise / Developer môže SQL Server zvoliť batch mode a Window Aggregate – potom rozdiel neuvidíš.)
## Čo s tým
1. Pre časté window dotazy: POC index (PARTITION BY stĺpce, ORDER BY stĺpce, INCLUDE ostatných).
2. Pri bežiacich súčtoch a priemeroch píš rámec explicitne: `ROWS UNBOUNDED PRECEDING`, ak je ORDER BY unikátny alebo ti duplicity nevadia.
3. Pri analytike nad veľkými tabuľkami zváž [columnstore a batch mode](script.php?id=81&s=columnstore-a-batch-mode-actual-execution-mode-segment-elimination).
## Súvisiace
- [Spools](script.php?id=78&s=spools-table-index-row-count-a-window-spool-eager-vs-lazy)
- [Sort, Top a Top N Sort](script.php?id=75&s=sort-top-a-top-n-sort-zoradovanie-a-pamat)
- [Columnstore a batch mode](script.php?id=81&s=columnstore-a-batch-mode-actual-execution-mode-segment-elimination)
- [Kto spotrebúva tempdb](script.php?id=20&s=kto-spotrebuva-tempdb)
## Zdroje
- [Microsoft Learn – SELECT – OVER clause](https://learn.microsoft.com/sql/t-sql/queries/select-over-clause-transact-sql)
- [Microsoft Learn – Showplan Logical and Physical Operators Reference](https://learn.microsoft.com/sql/relational-databases/showplan-logical-and-physical-operators-reference)
- [Hugo Kornelis – SQL Server Execution Plan Reference (SQLServerFast)](https://sqlserverfast.com/epr/)
- [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._Window funkcie v pláne – Segment, Sequence Project a Window Spool
ROW_NUMBER, RANK a SUM() OVER v pláne: Sort, Segment, Sequence Project, Window Spool (rámec RANGE na disku vs. ROWS v pamäti), Window Aggregate v batch mode a POC index.