> [!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á  `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._
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.