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

Skalárna T-SQL funkcia (**scalar UDF**) sa v klasickom pláne „schová“ do **Compute Scalar** s nákladom okolo 0 %. Multi-statement table-valued funkcia (**MSTVF**) je operátor **Table Valued Function** + často **Table Scan** jej výsledku. Inline table-valued funkcia (**iTVF**) v pláne nie je vidieť ako funkcia – jej dotaz sa vloží do plánu ako pohľad.
## Čo to znamená
- **Scalar UDF bez inliningu** sa vykoná **pre každý riadok** ako samostatný malý dotaz. V pláne volajúceho dotazu jej prácu nevidíš (má vlastný plán), náklad je zavádzajúci a celý plán ostane **sériový**.
- **Scalar UDF inlining** (SQL Server 2019+, compat 150) – ak funkcia spĺňa podmienky, jej telo sa vloží do plánu ako výraz / poddotaz. Výsledok býva rádovo rýchlejší.
- **MSTVF** – výsledok sa najprv naplní do tabuľkovej premennej. Optimalizátor pevne odhaduje počet riadkov (**1** pri legacy CE, **100** pri CE 120+), pokiaľ nepomôže *interleaved execution* (SQL Server 2017+, compat 140): funkcia sa vykoná skôr a skutočný počet riadkov sa použije pri optimalizácii zvyšku dotazu.
- **iTVF** je najlepšia voľba – je to len parametrizovaný pohľad a optimalizátor vidí celý dotaz.
### Do hĺbky
- Či sa dá scalar UDF inlinovať, ukáže `sys.sql_modules.is_inlineable`. Bráni tomu napr. volanie nedeterministickej funkcie (GETDATE), table variable, cykly, niektoré konštrukcie – zoznam je v dokumentácii.
- Inlining vypneš pre funkciu `WITH INLINE = OFF`, pre dotaz hintom `USE HINT('DISABLE_TSQL_SCALAR_UDF_INLINING')`, pre databázu `TSQL_SCALAR_UDF_INLINING = OFF`.
- Bez inliningu: **NonParallelPlanReason** na SELECT (napr. `TSQLUserDefinedFunctionsNotParallelizable` v novších verziách), čas funkcie sa ukáže v *QueryTimeStats* (UdfCpuTime, UdfElapsedTime) a čítania vnútri funkcie nie sú pri tabuľkách volajúceho dotazu v STATISTICS IO.
- Funkcia v **WHERE** alebo **JOIN** podmienke (`WHERE dbo.fn(x) = 1`) je navyše [non-SARGable](script.php?id=89&s=non-sargable-podmienky-funkcia-na-stlpci-like-x-or).
- Scalar UDF v **computed column** alebo **CHECK constrainte** zabráni paralelizmu aj dotazom, ktoré tú tabuľku len čítajú.
## Kedy je to v poriadku / kedy problém
| V poriadku | Problém |
|---|---|
| iTVF | scalar UDF s prístupom k tabuľkám nad tisíckami riadkov |
| inlinovaná scalar UDF (2019+) | NonParallelPlanReason kvôli UDF pri veľkom reporte |
| MSTVF s pár riadkami | MSTVF s odhadom 100 a skutočnosťou 1 000 000 |
## Ako si to vyskúšať
```sql
USE PlanLab;
GO
CREATE OR ALTER FUNCTION dbo.fn_Lab_OrderCount (@CustomerID int)
RETURNS int
AS
BEGIN
RETURN (SELECT COUNT(*) FROM dbo.Orders WHERE CustomerID = @CustomerID);
END;
GO
SET STATISTICS IO, TIME ON;
-- 1) Pred 2019 / compat 140: funkcia 1 000-krát, „neviditeľná“ v pláne
ALTER DATABASE PlanLab SET COMPATIBILITY_LEVEL = 140;
GO
SELECT TOP (1000) CustomerID, dbo.fn_Lab_OrderCount(CustomerID) AS pocet FROM dbo.Customers;
GO
-- 2) SQL Server 2019+: compat 150 → inlining (ak is_inlineable = 1)
ALTER DATABASE PlanLab SET COMPATIBILITY_LEVEL = 150;
GO
SELECT TOP (1000) CustomerID, dbo.fn_Lab_OrderCount(CustomerID) AS pocet FROM dbo.Customers;
SELECT OBJECT_NAME(object_id) AS funkcia, is_inlineable FROM sys.sql_modules WHERE object_id = OBJECT_ID(N'dbo.fn_Lab_OrderCount');
GO
-- 3) Rovnaká logika ako iTVF – vždy súčasť plánu
CREATE OR ALTER FUNCTION dbo.tvf_Lab_OrderCount (@CustomerID int)
RETURNS TABLE
AS RETURN (SELECT COUNT(*) AS pocet FROM dbo.Orders WHERE CustomerID = @CustomerID);
GO
SELECT TOP (1000) c.CustomerID, x.pocet FROM dbo.Customers AS c CROSS APPLY dbo.tvf_Lab_OrderCount(c.CustomerID) AS x;
GO
DROP FUNCTION dbo.fn_Lab_OrderCount;
DROP FUNCTION dbo.tvf_Lab_OrderCount;
```
Spusti s **Include Actual Execution Plan** (Ctrl+M). V bode 1 pozri na SELECT *NonParallelPlanReason* a *QueryTimeStats*, v bode 2 porovnaj tvar plánu. Compat level vráť na pôvodnú hodnotu (pozri výsledok skriptu [PlanLab](script.php?id=65&s=planlab-testovacia-databaza-pre-recepty-exekucnych-planov)).
## Čo s tým
1. Na SQL Server 2019+ over compat level 150+ a `is_inlineable` – často stačí, aby funkcie prestali škodiť.
2. Ak sa funkcia inlinovať nedá: prepíš ju na **inline table-valued** funkciu a volaj cez `CROSS APPLY`, alebo logiku vlož priamo do dotazu.
3. MSTVF s veľkým výsledkom nahraď iTVF alebo #temp tabuľkou (so štatistikami – [Table variable vs. #temp](script.php?id=86&s=table-variable-vs-temp-tabulka-odhady-a-deferred-compilation-2019)).
4. Odstráň scalar UDF z computed columns a CHECK constraintov na veľkých tabuľkách.
## Súvisiace
- [Compute Scalar, Filter a ďalšie malé operátory](script.php?id=77&s=compute-scalar-filter-constant-scan-a-concatenation-male-operatory)
- [RBAR – kurzory a cykly](script.php?id=94&s=rbar-kurzory-cykly-a-funkcie-po-riadkoch-v-plane)
- [Table variable vs. #temp](script.php?id=86&s=table-variable-vs-temp-tabulka-odhady-a-deferred-compilation-2019)
- [Paralelizmus – cost threshold, MAXDOP](script.php?id=93&s=paralelizmus-cost-threshold-maxdop-a-cxpacket-cxconsumer)
- [Hľadanie textu v procedúrach a funkciách](script.php?id=43&s=hladanie-textu-v-procedurach-view-a-funkciach)
## Zdroje
- [Microsoft Learn – Scalar UDF inlining](https://learn.microsoft.com/sql/relational-databases/user-defined-functions/scalar-udf-inlining)
- [Microsoft Learn – Intelligent query processing details](https://learn.microsoft.com/sql/relational-databases/performance/intelligent-query-processing-details)
- [Microsoft Learn – Intelligent query processing](https://learn.microsoft.com/sql/relational-databases/performance/intelligent-query-processing)
- [Hugo Kornelis – SQL Server Execution Plan Reference (SQLServerFast)](https://sqlserverfast.com/epr/)
- [Erik Darling – blog (plány, memory grants, parameter sniffing)](https://erikdarling.com/)
_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._Funkcie v pláne – scalar UDF, inlining (2019+) a table-valued funkcie
Ako vyzerajú funkcie v pláne: skalárna UDF skrytá v Compute Scalar, sériový plán, scalar UDF inlining v SQL Server 2019+, MSTVF s pevným odhadom, interleaved execution a inline TVF.