> [!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 SSMS: **Clustered Index Insert / Update / Delete** (alebo **Table Insert…** pri halde), **Index Insert / Update / Delete** pre neklastrované indexy, **Split**, **Sort**, **Collapse**, **Assert** a pri cudzích kľúčoch Nested Loops (Left Semi Join) so seekom do druhej tabuľky. Koreň plánu je `INSERT`, `UPDATE`, `DELETE` alebo `MERGE`.
## Čo to znamená
Plán zmeny má dve časti: **vyhľadanie riadkov** (napravo – rovnaké operátory ako pri SELECT) a **zápis** (vľavo). Zápis musí upraviť tabuľku aj **všetky dotknuté indexy** a overiť **constrainty**.
### Do hĺbky
- **Narrow plán** (*per-row*) – jeden operátor zmení klastrovaný index aj neklastrované indexy naraz; zoznam indexov je vo vlastnosti *Object*. Typické pre malé zmeny.
- **Wide plán** (*per-index*) – pre každý index samostatný operátor, často so **Sort** podľa kľúča indexu (zápis v poradí = menej náhodných I/O) a s **Table Spool**, ktorý rozdelí prúd riadkov. Typické pre veľké zmeny.
- **Split / Sort / Collapse** – pri UPDATE stĺpca kľúča indexu: Split rozdelí update na delete + insert, Collapse ich spojí späť, ak sa týkajú toho istého kľúča (ochrana pred falošnými porušeniami unikátnosti).
- **Assert** – kontrola, ktorá pri neplatnej hodnote vyhodí chybu: CHECK constraint, cudzí kľúč, aj poddotaz, ktorý má vrátiť jednu hodnotu (chyba „Subquery returned more than 1 value“ pochádza z Assert).
- **Cudzí kľúč**: pri INSERT/UPDATE do podriadenej tabuľky seek do nadradenej; pri DELETE z nadradenej seek do podriadenej. Bez indexu na stĺpcoch FK v podriadenej tabuľke je to **sken** pri každom DELETE nadradeného riadku.
- **Halloween protection** – Eager Table Spool medzi čítaním a zápisom, keď by zápis mohol ovplyvniť vlastné čítanie ([Spools](script.php?id=78&s=spools-table-index-row-count-a-window-spool-eager-vs-lazy)).
- **Triggery** v pláne nie sú – majú vlastný plán (v SSMS ako ďalší plán v poradí).
- Zmeny sa logujú: čakanie `WRITELOG` je cena za commit, nie chyba plánu ([Čakania](waits.php#WRITELOG)).
## Kedy je to v poriadku / kedy problém
| V poriadku | Problém |
|---|---|
| narrow plán pri malých zmenách | DELETE z nadradenej tabuľky so skenom podriadenej (chýba index na FK) |
| wide plán so Sort pri veľkých dávkach | Sort pred Index Update so spillom |
| Assert bez nákladu | Table Spool (Halloween) pri miliónoch riadkov |
## Ako si to vyskúšať
```sql
USE PlanLab;
-- cudzí kľúč OrderLines → Orders (len v PlanLab)
ALTER TABLE dbo.OrderLines ADD CONSTRAINT FK_Lab_OrderLines_Orders FOREIGN KEY (OrderID) REFERENCES dbo.Orders (OrderID);
GO
BEGIN TRAN;
-- 1) INSERT: Clustered Index Insert + kontrola FK (seek do Orders) + Assert
INSERT dbo.OrderLines (OrderID, LineNum, ProductID, Qty, Price) VALUES (42, 9, 1, 1, 10);
-- 2) UPDATE stĺpca s indexom: pozri, či je plán narrow alebo wide
UPDATE dbo.Orders SET CustomerID = CustomerID + 1 WHERE OrderID <= 100000;
-- 3) DELETE nadradeného riadku: kontrola podriadenej tabuľky (tu cez PK_OrderLines; skončí chybou FK)
-- DELETE dbo.Orders WHERE OrderID = 5; -- skús len ako odhadovaný plán (Ctrl+L)
ROLLBACK;
GO
ALTER TABLE dbo.OrderLines DROP CONSTRAINT FK_Lab_OrderLines_Orders;
```
Spusti s **Include Actual Execution Plan** (Ctrl+M). Všetko je v transakcii s ROLLBACK – dáta sa nezmenia. DELETE z bodu 3 zobraz cez **Display Estimated Execution Plan** (Ctrl+L): uvidíš kontrolu podriadenej tabuľky a Assert. Pri UPDATE otvor F4 na zápisovom operátore a pozri *Object* (zoznam indexov).
## Čo s tým
1. Indexuj stĺpce cudzích kľúčov v podriadených tabuľkách – inak DELETE / UPDATE nadradených riadkov skenuje.
2. Veľké zmeny rob po dávkach (napr. 5 000 – 50 000 riadkov) – menší log, kratšie transakcie, menšie Sort a spooly.
3. Zbytočné indexy spomaľujú každý zápis – [Používanie indexov](script.php?id=27&s=pouzivanie-indexov-seeks-scans-lookups-updates) ukáže indexy, ktoré sa len udržiavajú.
4. Pri pomalom zápise pozri aj trigger (vlastný plán) a čakania na log.
## Súvisiace
- [Spools](script.php?id=78&s=spools-table-index-row-count-a-window-spool-eager-vs-lazy)
- [Nested Loops](script.php?id=71&s=nested-loops-vnorene-cykly-outer-a-inner-vstup)
- [Používanie indexov](script.php?id=27&s=pouzivanie-indexov-seeks-scans-lookups-updates)
- [Nedôveryhodné a vypnuté constraints](script.php?id=45&s=nedoveryhodne-a-vypnute-constraints)
- [Čakanie WRITELOG](waits.php#WRITELOG)
## Zdroje
- [Microsoft Learn – Showplan Logical and Physical Operators Reference](https://learn.microsoft.com/sql/relational-databases/showplan-logical-and-physical-operators-reference)
- [Hugo Kornelis – SQL Server Execution Plan Reference (SQLServerFast)](https://sqlserverfast.com/epr/)
- [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._INSERT, UPDATE a DELETE v pláne – narrow vs. wide plán, Assert
Plány zmien dát: Clustered Index Insert / Update / Delete, narrow vs. wide plán, Split / Sort / Collapse, Assert pre CHECK a cudzie kľúče, Halloween protection a triggery.