Preskočiť na obsah
Návod

SET STATISTICS IO, TIME – čítanie výstupu vedľa plánu

Ako čítať logical reads, physical reads, Scan count, Worktable a CPU vs. elapsed time zo SET STATISTICS IO, TIME a ako nimi overiť, či zmena plánu pomohla.

4 min čítania 4 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ýstup SET STATISTICS IO a TIME](uploads/2026/11/plan-z2.svg "Messages: logical reads na porovnanie pred / po, CPU vs. elapsed čas")

`SET STATISTICS IO, TIME ON` nič nemení na pláne – len do záložky *Messages* vypíše, koľko čítaní a času dotaz stál. Je to „váha“, ktorou overíš, či zmena plánu naozaj pomohla.

## Čo to znamená

- **logical reads** – koľko 8 KB stránok dotaz prečítal z pamäte (buffer pool). Najstabilnejšie číslo na porovnanie, lebo nezávisí od toho, či stránka bola na disku.
- **physical reads / read-ahead reads** – koľko stránok sa muselo načítať z disku (pri studenej cache). Pri opakovanom spustení zvyčajne klesnú na 0.
- **Scan count** – počet prístupov k objektu (napr. seekov alebo skenov jednotlivých vlákien). **Nie je** to „koľkokrát sa prečítala celá tabuľka“.
- **CPU time** vs. **elapsed time** – čistý procesorový čas a čas na hodinách. Pri paralelnom pláne môže byť CPU **väčší** ako elapsed (pracuje viac vlákien naraz).

### Do hĺbky

- Riadok **Worktable** = pracovná tabuľka v tempdb (spool, sort s veľkým vstupom, Merge Join many-to-many, kurzor). **Workfile** = súbor pre hash operácie, ktoré sa nevošli do pamäte. Nenulové hodnoty pri nich znamenajú prácu v tempdb.
- **lob logical reads** = čítanie LOB stĺpcov (`varchar(max)`, `nvarchar(max)`, `xml`) a columnstore segmentov.
- *parse and compile time* je čas kompilácie – pri opakovanom spustení s plánom z cache je 0 ms.
- Čísla sú za celý príkaz. Pri viacerých príkazoch v dávke sa vypíšu pre každý zvlášť.
- Funkcie (scalar UDF, multi-statement TVF) svoje čítania často **nezapočítajú** do riadku tabuľky volajúceho dotazu – viď [Funkcie v pláne](script.php?id=83&s=funkcie-v-plane-scalar-udf-inlining-2019-a-table-valued-funkcie).

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

| Signál | Čo to zvyčajne znamená |
|---|---|
| logical reads ≫ počet stránok tabuľky | opakované čítania – Key Lookup alebo vnútorná strana Nested Loops |
| logical reads ≈ veľkosť tabuľky, výsledok pár riadkov | sken – chýba index alebo podmienka nie je SARGable |
| Worktable / Workfile s veľkými číslami | spool, spill alebo many-to-many Merge Join |
| elapsed ≫ CPU | dotaz čaká (disk, sieť, iné session) – pozri WaitStats v pláne |
| CPU > elapsed | paralelný plán – v poriadku, ak je to žiaduce |

## Ako si to vyskúšať

```sql
USE PlanLab;
SET STATISTICS IO, TIME ON;

-- A: seek + key lookup pre malého zákazníka (pár desiatok čítaní)
SELECT OrderID, Amount, Note FROM dbo.Orders WHERE CustomerID = 42;

-- B: veľký zákazník – ten istý dotaz, iné čísla (sken alebo veľa lookupov)
SELECT OrderID, Amount, Note FROM dbo.Orders WHERE CustomerID = 1;

-- C: funkcia na stĺpci – sken celého indexu
SELECT COUNT(*) FROM dbo.Orders WHERE YEAR(OrderDate) = 2025;

-- D: rovnaký výsledok ako C, SARGable rozsah – seek
SELECT COUNT(*) FROM dbo.Orders WHERE OrderDate >= '20250101' AND OrderDate < '20260101';

SET STATISTICS IO, TIME OFF;
```

Spusti s **Include Actual Execution Plan** (Ctrl+M) a porovnaj v *Messages* logical reads pri C a D. Plán a čísla si vždy čítaj spolu.

## Čo s tým

1. Pred každou zmenou si ulož **logical reads a CPU time** (aj plán). Po zmene porovnaj.
2. Hľadaj tabuľku s najväčším počtom logical reads – zvyčajne zodpovedá najdrahšej vetve plánu.
3. Na prehľadnejšie čítanie vlož celý výstup *Messages* do nástroja na formátovanie (napr. statisticsparser.com) – sčíta tabuľky a časy.
4. Na produkcii namiesto spúšťania použi súhrnné čísla z cache alebo Query Store ([Top 20 dotazov podľa CPU](script.php?id=5&s=top-20-dotazov-podla-cpu)).

## Súvisiace

- [Exekučné plány – kuchárka](script.php?id=64&s=exekucne-plany-kucharka-zacni-tu)
- [Ako získať exekučný plán](script.php?id=66&s=ako-ziskat-exekucny-plan-ssms-plan-cache-query-store-extended-events)
- [Key Lookup a RID Lookup](script.php?id=70&s=key-lookup-a-rid-lookup-dohladanie-chybajucich-stlpcov)
- [Spill do tempdb](script.php?id=90&s=spill-do-tempdb-sort-a-hash-warning-memory-grant-feedback)
- [Top 20 dotazov podľa CPU](script.php?id=5&s=top-20-dotazov-podla-cpu)
- [I/O latencia podľa súborov](script.php?id=23&s=i-o-latencia-podla-databazovych-suborov)

## Zdroje

- [Microsoft Learn – SET STATISTICS IO](https://learn.microsoft.com/sql/t-sql/statements/set-statistics-io-transact-sql)
- [Microsoft Learn – SET STATISTICS TIME](https://learn.microsoft.com/sql/t-sql/statements/set-statistics-time-transact-sql)
- [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._