Preskočiť na obsah
Návod

Implicitná konverzia (CONVERT_IMPLICIT) – varchar vs. nvarchar

CONVERT_IMPLICIT v pláne: priorita dátových typov, varchar stĺpec a nvarchar parameter, varovanie SeekPlan / CardinalityEstimate, vplyv kolácie a ako typy zosúladiť.

3 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

![Index Scan s CONVERT_IMPLICIT na stĺpci a varovaním](uploads/2026/11/plan-p5.svg "Konverzia stĺpca v každom riadku zabráni hľadaniu v indexe")

V *Predicate* alebo *Seek Predicates* vidíš **CONVERT_IMPLICIT(…)** okolo **stĺpca** a na SELECT žltý trojuholník s varovaním *Type conversion in expression (CONVERT_IMPLICIT(…)) may affect "CardinalityEstimate"* alebo *"SeekPlan" in query plan choice*.

## Čo to znamená

Keď porovnávaš dve hodnoty rôznych typov, SQL Server jednu prevedie na typ druhej podľa **priority dátových typov** (*data type precedence*). `nvarchar` má vyššiu prioritu ako `varchar`, takže pri `WHERE AccountCode = N'AC000123'` (alebo parameter `nvarchar` z aplikácie) sa prevádza **stĺpec** – v každom riadku. Index na stĺpci potom nejde použiť obvyklým spôsobom a odhad je horší.

### Do hĺbky

- Najčastejšie páry: `varchar` stĺpec vs. `nvarchar` parameter (ORM, .NET reťazce sú predvolene nvarchar), `int` stĺpec vs. `varchar` hodnota, `date` vs. `datetime2`, rôzne kolácie.
- Pri **Windows kolácii** (napr. `Latin1_General_CI_AS`) vie SQL Server aj s konverziou urobiť seek cez rozsah (*GetRangeThroughConvert*, v pláne Compute Scalar + Constant Scan + Nested Loops pred seekom) – odhad je však horší. Pri **SQL kolácii** (`SQL_Latin1_General_CP1_CI_AS`) skončí `varchar` stĺpec s `nvarchar` hodnotou **skenom**.
- Konverzia **parametra** (nie stĺpca) je v poriadku – napr. `int` stĺpec a `smallint` parameter.
- Varovanie *may affect CardinalityEstimate* sa objavuje aj pri konverziách v SELECT zozname, kde nevadí – rozhodujúce je, či je konverzia na stĺpci vo WHERE / JOIN.

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

| V poriadku | Problém |
|---|---|
| konverzia konštanty alebo parametra | CONVERT_IMPLICIT na stĺpci vo WHERE / JOIN |
| varovanie pri výraze vo výstupe | sken veľkej tabuľky, hoci index na stĺpci existuje |

## Ako si to vyskúšať

```sql
USE PlanLab;
SET STATISTICS IO ON;
-- 1) Správny typ (varchar) → Index Seek
SELECT OrderID FROM dbo.Orders WHERE AccountCode = 'AC000123';

-- 2) nvarchar konštanta → CONVERT_IMPLICIT na stĺpci (podľa kolácie seek cez rozsah alebo sken)
SELECT OrderID FROM dbo.Orders WHERE AccountCode = N'AC000123';

-- 3) Tak to robí aplikácia: nvarchar parameter
EXEC sys.sp_executesql N'SELECT OrderID FROM dbo.Orders WHERE AccountCode = @p', N'@p nvarchar(20)', @p = N'AC000123';

-- 4) Oprava na strane volajúceho: správny typ parametra
EXEC sys.sp_executesql N'SELECT OrderID FROM dbo.Orders WHERE AccountCode = @p', N'@p varchar(20)', @p = 'AC000123';

-- kolácia databázy
SELECT DATABASEPROPERTYEX(N'PlanLab', 'Collation') AS kolacia;
```

Spusti s **Include Actual Execution Plan** (Ctrl+M), pri bodoch 2 a 3 nájdi varovanie na SELECT a *Predicate* / *Seek Predicates* s CONVERT_IMPLICIT.

## Čo s tým

1. **Oprav typ na strane volajúceho**: parameter rovnakého typu a dĺžky ako stĺpec (v .NET `SqlDbType.VarChar`, v ORM mapovanie stĺpca ako ansi / `varchar`).
2. V T-SQL: premenné a parametre deklaruj typom stĺpca; konštanty pre varchar stĺpce píš bez `N` prefixu.
3. Ak sa volajúci zmeniť nedá: zváž zmenu typu stĺpca (dlhodobé riešenie, pozor na veľkosť a závislosti) alebo computed column s indexom.
4. Hľadaj konverzie v cache: plány s textom `CONVERT_IMPLICIT` (napr. cez [Top 20 dotazov podľa CPU](script.php?id=5&s=top-20-dotazov-podla-cpu) a XML plánu).

## Súvisiace

- [Non-SARGable podmienky](script.php?id=89&s=non-sargable-podmienky-funkcia-na-stlpci-like-x-or)
- [Index Seek – seek vs. residual predicate](script.php?id=69&s=index-seek-seek-predicate-vs-residual-predicate)
- [Varovania v pláne](script.php?id=96&s=varovania-v-plane-zlty-trojuholnik-no-join-predicate-no-statistics)
- [Table Scan a Clustered Index Scan](script.php?id=68&s=table-scan-a-clustered-index-scan-citanie-celej-tabulky)

## Zdroje

- [Microsoft Learn – Data type precedence](https://learn.microsoft.com/sql/t-sql/data-types/data-type-precedence-transact-sql)
- [Microsoft Learn – Data type conversion (Database Engine)](https://learn.microsoft.com/sql/t-sql/data-types/data-type-conversion-database-engine)
- [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/)

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