> [!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 skutočnom pláne pri operátore: *Estimated Number of Rows Per Execution* (× *Estimated Number of Executions*) proti *Actual Number of Rows for All Executions*. SSMS ukazuje pod operátorom aj „1 200 of 12 (10 000 %)“ – skutočnosť z odhadu.
## Čo to znamená
Optimalizátor vyberá plán podľa **odhadovaných** počtov riadkov. Keď odhadne 12 a príde 98 400, zvolí plán pre malé čísla: Nested Loops, Key Lookup, malý memory grant. Pri skutočných číslach je taký plán pomalý. **Väčšina zlých plánov je dôsledkom zlého odhadu, nie zlého optimalizátora.**
### Do hĺbky
- Odhady pochádzajú zo **štatistík**: histogram (max. 200 krokov) prvého stĺpca, hustota (density) pre kombinácie stĺpcov, počet riadkov tabuľky.
- **Zastarané štatistiky** – automatický update sa spustí až po určitom počte zmien. Od SQL Server 2016 (compat 130) je prah dynamický (pri veľkých tabuľkách nižší ako 20 %), ale stále môže byť veľa zmien „mimo histogramu“.
- **Ascending key** – nové hodnoty (dnešný dátum, rastúce ID) sú za koncom histogramu. Legacy CE pre ne odhaduje 1 riadok; nový CE (120+) predpokladá priemernú hustotu – lepšie, ale nie presné.
- **Korelované stĺpce** – `City = 'Praha' AND Country = 'CZ'`: CE predpokladá (čiastočnú) nezávislosť a odhad podhodnotí.
- **Lokálne premenné** (`DECLARE @d date = …; WHERE OrderDate = @d`) – hodnotu optimalizátor nevidí, použije priemernú hustotu.
- **Výrazy a funkcie** na stĺpci, table variable, MSTVF – pevné odhady ([table variable](script.php?id=86&s=table-variable-vs-temp-tabulka-odhady-a-deferred-compilation-2019), [funkcie](script.php?id=83&s=funkcie-v-plane-scalar-udf-inlining-2019-a-table-valued-funkcie)).
- Chyba sa **šíri doľava**: zlý odhad na začiatku ovplyvní všetky ďalšie operátory. Opravuj **prvý** (najpravší) rozdiel.
- Na SELECT: *OptimizerStatsUsage* ukáže, ktoré štatistiky sa použili a kedy boli aktualizované; varovanie *Columns With No Statistics* = štatistika chýba ([Varovania](script.php?id=96&s=varovania-v-plane-zlty-trojuholnik-no-join-predicate-no-statistics)).
## Kedy je to v poriadku / kedy problém
| V poriadku | Problém |
|---|---|
| rozdiel do ~10× pri malých číslach | rozdiel 100× a viac, najmä keď mení typ spojenia |
| zlý odhad na konci plánu, ktorý už nič nemení | zlý odhad pri Index Seek vpravo → Nested Loops a Key Lookup pre tisíce riadkov |
| | spill, malý memory grant, sériový plán kvôli malému odhadu |
## Ako si to vyskúšať
```sql
USE PlanLab;
-- 1) Presný odhad (štatistiky z indexu sú čerstvé)
SELECT OrderID, Amount FROM dbo.Orders WHERE OrderDate = '20260115';
-- 2) Ascending key: pridáme 10 000 objednávok s budúcim dátumom (mimo histogramu a pod prahom auto update – pri 300 000 riadkoch je to ≈ 17 300 zmien)
INSERT dbo.Orders (CustomerID, OrderDate, Status, Amount, AccountCode)
SELECT TOP (10000) 5, '20261231', 1, 10, 'AC000001' FROM sys.all_columns AS a CROSS JOIN sys.all_columns AS b;
SELECT OrderID, Amount FROM dbo.Orders WHERE OrderDate = '20261231' OPTION (RECOMPILE); -- porovnaj odhad / skutočnosť
-- 3) Lokálna premenná: optimalizátor hodnotu nevidí
DECLARE @d date = '20260115';
SELECT OrderID, Amount FROM dbo.Orders WHERE OrderDate = @d;
-- 4) Oprava: update štatistiky a znova
UPDATE STATISTICS dbo.Orders IX_Orders_OrderDate WITH FULLSCAN;
SELECT OrderID, Amount FROM dbo.Orders WHERE OrderDate = '20261231' OPTION (RECOMPILE);
-- histogram
DBCC SHOW_STATISTICS ('dbo.Orders', 'IX_Orders_OrderDate') WITH HISTOGRAM;
-- upratanie: DELETE dbo.Orders WHERE OrderDate = '20261231'; (alebo znova skript PlanLab)
```
Spusti s **Include Actual Execution Plan** (Ctrl+M) a pri Index Seek porovnaj odhad a skutočnosť pred a po UPDATE STATISTICS.
## Čo s tým
1. Nájdi **prvý** operátor sprava s veľkým rozdielom a zisti, odkiaľ odhad pochádza (štatistika, premenná, funkcia).
2. **Aktualizuj štatistiky** (aj s väčším vzorkovaním / FULLSCAN) – [Štatistiky – posledný update](script.php?id=29&s=statistiky-posledny-update-a-pocet-zmien). Pri rýchlo rastúcich tabuľkách plánuj častejší update.
3. **Prepíš dotaz**: SARGable podmienky, parametre namiesto lokálnych premenných (alebo `OPTION (RECOMPILE)`), #temp namiesto table variable, rozdelenie zložitého dotazu na kroky.
4. Pri korelovaných stĺpcoch: viacstĺpcové štatistiky alebo filtrované štatistiky.
5. Až potom hinty (`OPTION (RECOMPILE)`, `USE HINT('ASSUME_JOIN_PREDICATE_DEPENDS_ON_FILTERS')`…) – a s komentárom prečo.
## Súvisiace
- [Cardinality estimator – CE 70 vs. 120+](script.php?id=85&s=cardinality-estimator-ce-70-vs-120-a-compat-level)
- [Table variable vs. #temp](script.php?id=86&s=table-variable-vs-temp-tabulka-odhady-a-deferred-compilation-2019)
- [Parameter sniffing](script.php?id=87&s=parameter-sniffing-jeden-plan-pre-rozne-hodnoty-psp-2022-oppo-2025)
- [Štatistiky – posledný update a počet zmien](script.php?id=29&s=statistiky-posledny-update-a-pocet-zmien)
- [Nested Loops](script.php?id=71&s=nested-loops-vnorene-cykly-outer-a-inner-vstup)
- [Key Lookup a RID Lookup](script.php?id=70&s=key-lookup-a-rid-lookup-dohladanie-chybajucich-stlpcov)
## Zdroje
- [Microsoft Learn – Statistics](https://learn.microsoft.com/sql/relational-databases/statistics/statistics)
- [Microsoft Learn – Cardinality Estimation (SQL Server)](https://learn.microsoft.com/sql/relational-databases/performance/cardinality-estimation-sql-server)
- [Paul White – SQLkiwi (články o optimalizátore a operátoroch)](https://www.sql.kiwi/)
- [Grant Fritchey – SQL Server Execution Plans, 3. vydanie (Redgate, e-kniha zadarmo)](https://www.red-gate.com/simple-talk/books/sql-server-execution-plans-third-edition/)
_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._Zlé odhady riadkov – odhad vs. skutočnosť a štatistiky
Prečo optimalizátor odhadne 12 riadkov a príde 100 000: štatistiky a histogram, ascending key, lokálne premenné, korelované stĺpce, šírenie chyby v pláne a ako odhad opraviť.