SQL Server’da veri türü dönüşümleri, veritabanı sistemlerinin en temel ve kritik işlemlerinden biridir. Bu makalede, Explicit (Açık) Conversion ve Implicit (Örtük) Conversion kavramlarını tüm detaylarıyla inceleyeceğiz. Veri bütünlüğü, sorgu performansı ve en iyi uygulamalar üzerinde duracağız.
Explicit Conversion (Açık Dönüşüm): Explicit conversion, geliştirici tarafından bilinçli olarak yapılan ve SQL ifadelerinde açıkça belirtilen dönüşüm türüdür. SQL Server’da CONVERT ve CAST operatörleri, bir veri türünü başka bir veri türüne dönüştürmek için kullanılır. Her ikisi de benzer işlev görür, ancak bazı farklılıkları vardır.
CAST ANSI SQL standardına uygundur ve bu nedenle diğer veri tabanı sistemlerinde de genellikle aynı şekilde çalışır.
CONVERT, SQL Server’a özgü bir fonksiyondur. Özellikle tarih-saat verilerini formatlama konusunda CAST’ten daha fazla kontrol sunar.
Genel dönüşümler için: CAST
Tarih-saat formatlama gerekiyorsa: CONVERT
-- CAST fonksiyonu (ANSI standardı)
SELECT CAST(123.456 AS INT) AS TamSayi
-- CONVERT fonksiyonu (SQL Server'a özel)
SELECT CONVERT(VARCHAR, GETDATE(), 104) AS Tarih
CONVERT fonksiyonu, CAST’tan farklı olarak format belirlemeye izin verir:
-- Tarih formatlama örnekleri
SELECT CONVERT(VARCHAR, GETDATE(), 101) -- 12/31/2023
SELECT CONVERT(VARCHAR, GETDATE(), 103) -- 31/12/2023
SELECT CONVERT(VARCHAR, GETDATE(), 112) -- 20231231
Execution plan ekranında şart bölümünde bazen convert işlemi görülür. Bu ifadenin sebebi sql server’da kullanıcının yazdığı sorguda değişkenin float türü olması sonucunda sql server KimlikNo kolonundaki veri türü farklı olmasından dolayı sql server arka planda ilgili tablonun ilgili kolonunda tüm satırları Float türüne dönüştürmektedir. Dikkat ederseniz açık bir işlemdir. Kullanıcı sorgunusun tablonun türüyle aynı olmamasından kaynaklanmaktadır. Büyük verilerin küçük boyutlara dönüştürülmesi performansı olumsuz etkileyebilir. Sql server genellikle küçük veriden büyük veriye kendisi karar vermektedir. Aşağıdaki resimlerde float bigint’ten daha büyük bir karakter olduğu için sql server kimlikno kolonunu float türüne dönüştürmektedir.


Sorgunun XML uzantısına bakıldığında dönüşüm işlemi gerçekleştiği görülmektedir.

Implicit Conversion (Örtük Dönüşüm): Implicit conversion, SQL Server tarafından otomatik olarak gerçekleştirilen ve sorgularda açıkça belirtilmeyen dönüşüm türüdür
-- Örnek 1: VARCHAR ile INT karşılaştırma
SELECT * FROM Musteriler WHERE MusteriNo = '1001' -- MusteriNo INT sütunu
-- Örnek 2: Farklı tarih formatları
SELECT * FROM Siparisler WHERE SiparisTarihi > '2023-01-01' -- Tarih tipi uyumsuzluğu
SQL Server’da varchar ile int arasında karşılaştırma yapılırsa, SQL Server her zaman varchar değeri → int’e dönüştürmeye çalışır (eğer mümkünse). Yani: Çünkü int veri tipi, varchar’dan daha yüksek önceliklidir (type precedence). SQL Server’daki veri türü önceliği sıralamasında int, varchar’dan üsttedir. Ayrıca ikinci komutta SQL Server, varchar değeri → datetime türüne dönüştürmeye çalışır.
Sıralamanın en üstünden (en yüksek öncelik) aşağıya doğru bazı önemli türler şöyledir:
- User-defined data types (En yüksek)
- datetimeoffset
- datetime2
- datetime
- float
- decimal
- bigint
- int
- smallint
- bit
- varchar / char (En altlara yakın)
Aşağıdaki tablo, en sık kullanılan veri türleri arasındaki geçiş imkanlarını özetler:
| Kaynak / Hedef | BIGINT | INT | DECIMAL | DATETIME | VARCHAR | BIT |
| BIGINT | – | Implicit | Implicit | Hayır | Explicit | Implicit |
| INT | Implicit | – | Implicit | Hayır | Explicit | Implicit |
| DECIMAL | Explicit | Explicit | – | Hayır | Explicit | Explicit |
| DATETIME | Hayır | Hayır | Hayır | – | Explicit | Hayır |
| VARCHAR | Explicit | Explicit | Explicit | Explicit | – | Explicit |
| BIT | Implicit | Implicit | Implicit | Hayır | Explicit | – |
Bir dönüşümün Implicit (Örtülü) sayılabilmesi için SQL Server’ın bu işlemi “her veri içeriğinde” hatasız yapabileceğini garanti etmesi gerekir.
- INT → BIGINT: Her zaman çalışır. Kayıp olmaz. (Implicit)
- VARCHAR → INT: Sadece string içinde rakam varsa çalışır. Eğer VARCHAR içinde “ABC” yazıyorsa SQL Server bunu INT’e çeviremez ve hata verir.
Bu yüzden teknik dokümanlarda VARCHAR’dan INT’e geçiş Explicit kategorisine alınır; çünkü SQL Server bu işlemi yaparken verinin içeriğine “bağımlıdır” ve riskli bir işlemdir.
Eğer SQL Server her VARCHAR’ı her zaman INT olarak görebilseydi, bu %100 implicit olurdu. Ancak VARCHAR çok geniş bir kümedir (harfler, semboller vb.). SQL Server bu geniş kümeyi daha dar bir küme olan INT’e otomatik olarak “varsayılan” olarak dönüştürmez. Sadece karşılaştırma anında Precedence kuralı devreye girdiği için sen onu örtülü bir şekilde gerçekleşirken görürsün.
Yukarıdaki sorgularda sql server arka planda tür dönüşümü yapmaktadır. Bu dönüşüm işlemleri execution plan tooltip pencerisinde gördükten sonra XML üzerinde görünmektedir.
Implicit conversion, execution plan’da şu şekilde tespit edilebilir:
SQL Server Management Studio (SSMS) üzerinde Execution Plan’a baktığınızda, operatörlerin üzerinde sarı bir ünlem (!) işareti görürsünüz. Bu tooltip (ipucu) penceresindeki ifadeler sizin için “erken uyarı sistemi” gibidir.
- Type Conversion (CONVERT_IMPLICIT): Eğer Tooltip içinde bu ifadeyi görüyorsanız, SQL Server size şunu demek istiyordur: “Ben burada iki veri tipini eşleştiremedim, arka planda gizli bir dönüştürme yapıyorum ve bu yüzden Index’i verimli kullanamıyor olabilirim.”
- Cardinality Estimation: Tooltip’te “Estimated Number of Rows” ile “Actual Number of Rows” arasında büyük fark varsa, bu yine veri türü uyumsuzluğundan kaynaklanan yanlış bir tahminleme yapıldığını gösterir.

Belirtilen kolonun türüne baktığımızda kolon türünün varchar(50) olduğu görülmektedir. Küçük boyutlu veri büyük boyutlu veriye dönüşüm işlemi yapılmaktadır.

Sorgumuzun execution planında bulunan XML uzantısına baktığımızda ise ilgili kolonda tüm satırların nvarchar(max) işlemine dönüştüğü görülmektedir.

Entity Framework/LINQ sorguları sık görülen implicit conversion kaynaklarıdır. Web API’den gelen tüm parametreler string olarak gelir. Uygun tip dönüşümü yapılmazsa implicit conversion oluşur. Frontend kodlarından gelen kaynaklarda görülmektedir. JavaScript’ten gelen verilerin tip kontrolü yapılmaması ve Form verilerinin uygun şekilde parse edilmemesidir.

Not: <PlanAffectingConvert ConvertIssue="Seek Plan" Expression="CONVERT_IMPLICIT(varchar(50),[f].[KNAD],0)=[k].[KRKLNAD]" /> Query plan’da bir implicit (örtük) veri tipi dönüşümü var. Bu dönüşüm, index seek kullanılmasını engelleyebilir veya verimsiz hale getirebilir. CONVERT_IMPLICIT(varchar(50), [f].[KNAD], 0) = [k].[KRKLNAD]
Bu şu demek: f.KNAD adlı sütun ile k.KRKLNAD arasında yapılan karşılaştırmada, SQL Server f.KNAD kolununu otomatik olarak varchar(50)’ye dönüştürüyor. Bu implicit convert, sorgunun index seek yapmasını engelleyip index scan yapmasına neden olabilir. Bu da performans kaybı demektir. Eğer biri varchar(50) diğeri nvarchar(50) ise, sql server düşük kolonu yüksek olan nvarchar(50) dönüşümü yapmaktadır..
Aşağıdaki sorgula implicit conversion yapılarını görebiliriz.
SELECT qp.query_plan
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
WHERE qp.query_plan.exist('//*:Convert[@Implicit="1"]') = 1
Dönen değerden execution planları açıp xml uzantısına tıklarsak implicit conversion yapısı görülebilir.


Ctrl-F tuşu ile ilgili arama yaptığımızda hangi kolonlar üzerinde olduğu görülmektedir.

Başka örnekler vermek gerekirse:
Değişken türü nvarchar(4000) kolon türü nvarchar(50) arasında nasıl bir dönüşüm olur. NVARCHAR(4000) değişkeni otomatik olarak NVARCHAR(50)’ye dönüştürülür. (implicit conversion). SQL Server, daha büyük boyutlu veriyi küçük boyuta dönüştürerek veri kesilmesi riskini kontrol altına alır. Veritabanı tasarımında belirlenen kolon boyutu (50 karakter) esas alınır.
Join yapılan iki kolondan birinci varchar(50) ikinci kolon varchar(15) implicit conversin hangi kolonda oluşur. VARCHAR(15) olan kolon, VARCHAR(50)’ye dönüştürülür. SQL Server, daha küçük boyutlu veriyi (15 karakter) daha büyük boyuta (50 karakter) dönüştürerek veri kesilmesi riskini ortadan kaldırır.
Not: XML bölümünün en altında sorgumuzun değerleri görülmektedir.
Aşağıdaki sorgu ile belirtilen veritabanı altında dönen sorgularda implicit conversion yapısının olduğu görülmektedir.
SELECT TOP 20
DB_NAME(st.dbid) AS [Veritabanı],
st.text AS [Sorgu Metni],
qp.query_plan AS [Sorgu Planı],
qs.execution_count AS [Çalışma Sayısı],
CAST(qp.query_plan AS XML).query('
declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
//ScalarOperator[contains(@ScalarString, "CONVERT_IMPLICIT")]
') AS [Dönüşüm Detayı]
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) AS st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp
WHERE
CAST(qp.query_plan AS NVARCHAR(MAX)) LIKE '%CONVERT_IMPLICIT%'
AND st.dbid = DB_ID('DB_NAME')
AND st.text NOT LIKE '%sys.dm_exec_query_stats%'
--ORDER BY qs.execution_count DESC;

Sorgu planında sorgumuzun execution plan yapısı görülebilir.

Dönüşüm detayına bakıldığında convert implicit ifadelerin xml uzantıları gözükmektedir.
<ScalarOperator xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" ScalarString="CONVERT_IMPLICIT(int,[Expr1073],0)">
<Convert DataType="int" Style="0" Implicit="1">
<ScalarOperator>
<Identifier>
<ColumnReference Column="Expr1073" />
</Identifier>
</ScalarOperator>
</Convert>
</ScalarOperator>
Performans Maliyeti: Implicit vs. Explicit
Performans açısından genellikle Implicit (Örtülü) dönüşüm, Explicit (Açık) dönüşümden daha tehlikeli ve yüksek maliyetlidir. Nedenini şu şekilde ayırabiliriz:
- Implicit (Örtülü) Dönüşümün Gizli Tehlikesi (Index Kill):Eğer bir VARCHAR sütununda arama yaparken filtre değerini INT olarak verirseniz, SQL Server Veri Türü Önceliği nedeniyle tablodaki tüm satırları tek tek INT’e çevirmeye çalışır.
- Sonuç: Mevcut bir Index olsa bile SQL Server bunu kullanamaz (Index Scan yapar). Milyonlarca satırlık bir tabloda bu, sorgunun saniyelerce hatta dakikalarca sürmesi demektir. CPU kullanımı tavan yapar.
- Explicit (Açık) Dönüşüm:Siz CAST veya CONVERT kullandığınızda, SQL Server’a ne yapacağını açıkça söylersiniz. Eğer dönüşümü filtre tarafında (sağ tarafta) yaparsanız, sütun orijinal haliyle kalır ve Index’ten tam verim alırsınız (Index Seek).
- Örnek: WHERE VarcharKolon = CAST(123 AS VARCHAR) ifadesi, WHERE VarcharKolon = 123 ifadesinden çok daha hızlıdır.
Özet Karşılaştırma
| Kriter | Implicit (Örtülü) | Explicit (Açık) |
| Kontrol | SQL Server’da (Kontrolsüz) | Yazılımcıda (Kontrollü) |
| Index Kullanımı | Çoğunlukla Bozar (Scan tetikler) | Doğru kullanılırsa Bozulmaz (Seek yapar) |
| CPU Maliyeti | Her satır için dönüşüm yapıldığından yüksektir | Daha düşüktür |
| Hata Riski | Beklenmedik “Conversion Failed” hataları | Hata yönetimi daha kolaydır (TRY_CAST) |
Başka makalede görüşmek dileğiyle..
Nefsini maddî ve mânevî kirlerden temizleyen kesinlikle kurtuluşa erecektir. (Şems suresi, 9. ayet)
