Preskočiť na obsah
Návod

Plan regression – nový horší plán a vynútenie cez Query Store

Keď dotaz zrazu spomalí kvôli novému plánu: Query Store a jeho plány v čase, Regressed Queries, vynútenie plánu (sp_query_store_force_plan), automatic plan correction a Query Store hints (2022+).

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 pláne

![Graf trvania dotazu podľa plánov v Query Store](uploads/2026/11/plan-p12.svg "Nový plán spomalil dotaz; vynútený starý plán vrátil výkon")

Rovnaký dotaz (query_id) má v **Query Store** viac plánov (plan_id) s výrazne iným trvaním. V SSMS: databáza → *Query Store* → **Regressed Queries** alebo **Tracked Queries** – graf s bodkami podľa plánov a tlačidlá *Force Plan* / *Unforce Plan* / *Compare Plans*.

## Čo to znamená

**Plan regression** = dotaz dostal nový plán a ten je horší. Príčiny: rekompilácia s inou hodnotou parametra ([parameter sniffing](script.php?id=87&s=parameter-sniffing-jeden-plan-pre-rozne-hodnoty-psp-2022-oppo-2025)), update štatistík, zmena dát, nový index alebo jeho zmazanie, zmena compat levelu / CE ([Cardinality estimator](script.php?id=85&s=cardinality-estimator-ce-70-vs-120-a-compat-level)), upgrade servera. Query Store si pamätá plány aj ich výkon v čase, takže vieš ukázať „kedy a čím“ – a dobrý plán **vynútiť**.

### Do hĺbky

- **Vynútenie plánu** – `sp_query_store_force_plan @query_id, @plan_id` (alebo tlačidlo v SSMS). Optimalizátor pri kompilácii použije vynútený tvar. Ak sa to nepodarí (zmazaný index, zmena schémy), dotaz beží s novým plánom a Query Store zapíše `force_failure_count` / `last_force_failure_reason_desc`.
- **Automatic plan correction** (2017+, `AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = ON)`) – SQL Server sám vynúti posledný dobrý plán pri zistenej regresii; odporúčania v `sys.dm_db_tuning_recommendations`.
- **Query Store hints** (2022+) – `sys.sp_query_store_set_hints` pridá hint (napr. RECOMPILE, MAXDOP, compat level) k dotazu bez zmeny kódu aplikácie.
- **Optimized plan forcing** (2022+) – vynútené plány sa kompilujú rýchlejšie (uložený postup optimalizácie).
- Query Store je pre nové databázy zapnutý predvolene od SQL Server 2022; v starších verziách ho treba zapnúť. Stav ukáže recept [Query Store – konfigurácia a stav](script.php?id=46&s=query-store-konfiguracia-a-stav).

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

| V poriadku | Problém |
|---|---|
| viac plánov s podobným výkonom | jeden plán rádovo pomalší a často používaný |
| vynútený plán ako dočasná oprava s poznámkou | stovky vynútených plánov, ktoré nikto neeviduje |
| | vynútenie zlyháva (force_failure_count > 0) |

## Ako si to vyskúšať

```sql
USE PlanLab;
ALTER DATABASE PlanLab SET QUERY_STORE = ON (OPERATION_MODE = READ_WRITE, QUERY_CAPTURE_MODE = ALL);
ALTER DATABASE PlanLab SET QUERY_STORE CLEAR;
GO
CREATE OR ALTER PROCEDURE dbo.Lab_Regress @CustomerID int AS
SELECT OrderID, Amount, Note FROM dbo.Orders WHERE CustomerID = @CustomerID;
GO
EXEC dbo.Lab_Regress 42;  EXEC dbo.Lab_Regress 42;  EXEC dbo.Lab_Regress 1;   -- plán A (seek + lookup)
EXEC sp_recompile N'dbo.Lab_Regress';
EXEC dbo.Lab_Regress 1;   EXEC dbo.Lab_Regress 42;  EXEC dbo.Lab_Regress 42;  -- plán B (sken)
GO
-- plány dotazu a ich výkon
SELECT q.query_id, p.plan_id, rs.count_executions, rs.avg_duration / 1000.0 AS avg_ms, rs.avg_logical_io_reads
FROM sys.query_store_query AS q
JOIN sys.query_store_plan AS p ON p.query_id = q.query_id
JOIN sys.query_store_runtime_stats AS rs ON rs.plan_id = p.plan_id
WHERE q.object_id = OBJECT_ID(N'dbo.Lab_Regress');

-- vynútenie (doplň čísla z výsledku) a zrušenie
-- EXEC sys.sp_query_store_force_plan @query_id = 1, @plan_id = 1;
-- EXEC sys.sp_query_store_unforce_plan @query_id = 1, @plan_id = 1;
GO
DROP PROCEDURE dbo.Lab_Regress;
-- ALTER DATABASE PlanLab SET QUERY_STORE = OFF;
```

Otvor v SSMS *Query Store* → *Tracked Queries*, zadaj query_id a porovnaj plány (*Compare Plans*). Všetko sa deje len v PlanLab.

## Čo s tým

1. Zisti, **ktorý plán bol dobrý** a **čo sa zmenilo** (štatistiky, parameter, index, compat level).
2. Ako rýchlu opravu vynúť dobrý plán (zaznač si to). Dlhodobo odstráň príčinu – vynútený plán môže časom prestať byť dobrý.
3. Pravidelne kontroluj [Query Store – regresie](script.php?id=26&s=query-store-regresie-24-h-vs-predoslych-24-h) a vynútené plány (`is_forced_plan = 1`, zlyhania vynútenia).
4. Pred upgrade / zmenou compat levelu zbieraj baseline v Query Store.

## Súvisiace

- [Query Store – regresie](script.php?id=26&s=query-store-regresie-24-h-vs-predoslych-24-h)
- [Query Store – konfigurácia a stav](script.php?id=46&s=query-store-konfiguracia-a-stav)
- [Query Store – top dotazy podľa CPU](script.php?id=25&s=query-store-top-dotazy-podla-cpu)
- [Parameter sniffing](script.php?id=87&s=parameter-sniffing-jeden-plan-pre-rozne-hodnoty-psp-2022-oppo-2025)
- [Cardinality estimator](script.php?id=85&s=cardinality-estimator-ce-70-vs-120-a-compat-level)
- [Ako získať exekučný plán](script.php?id=66&s=ako-ziskat-exekucny-plan-ssms-plan-cache-query-store-extended-events)

## Zdroje

- [Microsoft Learn – Monitor performance by using the Query Store](https://learn.microsoft.com/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store)
- [Microsoft Learn – sp_query_store_force_plan](https://learn.microsoft.com/sql/relational-databases/system-stored-procedures/sp-query-store-force-plan-transact-sql)
- [Microsoft Learn – Query Store hints](https://learn.microsoft.com/sql/relational-databases/performance/query-store-hints)
- [Microsoft Learn – Intelligent query processing](https://learn.microsoft.com/sql/relational-databases/performance/intelligent-query-processing)

_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._