> [!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  Index na stĺpci existuje, ale v pláne je **Index Scan / Clustered Index Scan** s *Predicate* obsahujúcim funkciu nad stĺpcom (`datepart(year, OrderDate)`, `isnull(Note, '')`), alebo seek s obrovským *Number of Rows Read*. ## Čo to znamená **SARGable** (*Search ARGument able*) podmienka je taká, ktorú vie index použiť na **hľadanie**: stĺpec je sám na jednej strane porovnania a druhá strana je hodnota. Keď stĺpec „zabalíš“ do funkcie alebo výpočtu, SQL Server musí výraz vypočítať pre **každý riadok** – index sa dá len prečítať celý. Navyše odhad počtu riadkov býva horší (pre výraz nemá štatistiku). ### Do hĺbky - Typické prípady: funkcia na stĺpci (`YEAR()`, `CONVERT()`, `ISNULL()`, `LEFT()`, `UPPER()`), aritmetika (`Amount * 1.2 > 1000`), [implicitná konverzia](script.php?id=88&s=implicitna-konverzia-convert-implicit-varchar-vs-nvarchar), `LIKE '%text'` (začiatok neznámy), skalárna UDF na stĺpci. - Niektoré výnimky optimalizátor zvláda: `CAST(datetime_stĺpec AS date) = '20260115'` sa dá premeniť na seek cez rozsah; `LIKE 'abc%'` je seek. - **OR** cez rôzne stĺpce: jeden index nestačí – výsledok je sken, alebo (ak existujú indexy na oba stĺpce) *index union* cez Concatenation. Prepis na `UNION ALL` / `UNION` dáva optimalizátoru jasné seeky. - „Catch-all“ dotazy `WHERE (@p IS NULL OR col = @p)` – jeden plán musí fungovať pre všetky kombinácie → sken. Riešenie: `OPTION (RECOMPILE)`, dynamické SQL, v SQL Server 2025 OPPO ([parameter sniffing](script.php?id=87&s=parameter-sniffing-jeden-plan-pre-rozne-hodnoty-psp-2022-oppo-2025)). - Ak výraz potrebuješ, **computed column** s indexom (persisted alebo nie) dá výrazu štatistiku aj index. ## Kedy je to v poriadku / kedy problém | V poriadku | Problém | |---|---| | funkcia na hodnote / parametri (`OrderDate >= DATEADD(DAY, -7, @d)`) | funkcia na stĺpci vo WHERE / JOIN veľkej tabuľky | | malá tabuľka | sken napriek existujúcemu indexu | ## Ako si to vyskúšať ```sql USE PlanLab; SET STATISTICS IO ON; SELECT COUNT(*) FROM dbo.Orders WHERE YEAR(OrderDate) = 2025; -- Index Scan SELECT COUNT(*) FROM dbo.Orders WHERE OrderDate >= '20250101' AND OrderDate < '20260101'; -- Index Seek SELECT COUNT(*) FROM dbo.Customers WHERE Email LIKE '%9@example.com'; -- sken SELECT COUNT(*) FROM dbo.Customers WHERE Email LIKE 'zakaznik19%'; -- seek SELECT OrderID FROM dbo.Orders WHERE CustomerID = 5 OR AccountCode = 'AC000123'; -- čo zvolí? SELECT OrderID FROM dbo.Orders WHERE CustomerID = 5 UNION SELECT OrderID FROM dbo.Orders WHERE AccountCode = 'AC000123'; -- dva seeky -- computed column pre výraz, ktorý potrebuješ ALTER TABLE dbo.Orders ADD OrderYear AS YEAR(OrderDate); CREATE INDEX IX_Lab_Orders_Year ON dbo.Orders (OrderYear); SELECT COUNT(*) FROM dbo.Orders WHERE YEAR(OrderDate) = 2025; -- optimalizátor použije index na computed column DROP INDEX IX_Lab_Orders_Year ON dbo.Orders; ALTER TABLE dbo.Orders DROP COLUMN OrderYear; ``` Spusti s **Include Actual Execution Plan** (Ctrl+M) a porovnaj typ operátora (Scan / Seek), *Predicate* a logical reads. ## Čo s tým 1. Prepíš podmienku tak, aby stĺpec ostal „holý“ – výpočet presuň na stranu hodnoty (rozsah dátumov namiesto YEAR, porovnanie bez ISNULL…). 2. OR cez rôzne stĺpce → UNION / UNION ALL alebo vhodné indexy. 3. Vyhľadávanie podľa konca textu → iný model (reverzný stĺpec s indexom, full-text), nie LIKE '%x'. 4. Výraz, bez ktorého sa nedá: computed column + index. ## Súvisiace - [Implicitná konverzia](script.php?id=88&s=implicitna-konverzia-convert-implicit-varchar-vs-nvarchar) - [Index Seek – seek vs. residual predicate](script.php?id=69&s=index-seek-seek-predicate-vs-residual-predicate) - [Table Scan a Clustered Index Scan](script.php?id=68&s=table-scan-a-clustered-index-scan-citanie-celej-tabulky) - [Parameter sniffing](script.php?id=87&s=parameter-sniffing-jeden-plan-pre-rozne-hodnoty-psp-2022-oppo-2025) - [Chýbajúce indexy – návrhy optimalizátora](script.php?id=28&s=chybajuce-indexy-navrhy-optimalizatora) ## Zdroje - [Microsoft Learn – Query Processing Architecture Guide](https://learn.microsoft.com/sql/relational-databases/query-processing-architecture-guide) - [Paul White – SQLkiwi (články o optimalizátore a operátoroch)](https://www.sql.kiwi/) - [Brent Ozar – blog a nástroje First Responder Kit](https://www.brentozar.com/) - [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._
Non-SARGable podmienky – funkcia na stĺpci, LIKE '%x', OR
Prečo index nepomôže, keď je stĺpec vo funkcii, výpočte alebo LIKE s % na začiatku: SARGable vs. non-SARGable podmienky, OR cez rôzne stĺpce, catch-all dotazy a computed column.