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.
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:
- Uyarı simgesi (Sarı ünlem işareti)
- CONVERT_IMPLICIT operatörü
- Key Lookup operatörünün beklenmedik artışı

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 değerini 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..
Execution Plan’da CONVERT_IMPLICIT arama aşağıdaki komutla yapılmaktadır.
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
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.
İmplicit conversion yapısında kolon türü datetime2(7) sorgudaki ilgi kolondaki değişken türü nvarchar(4000) hangisi hangisine dönüşmektedir. SQL Server’da bir sorguda datetime2(7) tipindeki bir sütun ile nvarchar(4000) tipindeki bir değişken karşılaştırıldığında, örtük dönüşüm (implicit conversion) kuralları devreye girer. nvarchar(4000) değeri, datetime2(7)’ye dönüştürülür. SQL Server’ın veri türü öncelik kurallarına göre datetime2, nvarchar’dan daha yüksek önceliğe sahiptir.
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.
Kolon varchar(50), değişken nvarchar(max) dönüşüm işlemi hangisinde yapılır. nvarchar(max)’a göre yapılmaktadır. Kolon türünün varchar(11), değişken türü numeric(38,0) ise dönüşüm işlemi numeric kolonuna göre yapılmaktadı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 DB_NAME(sql_text.[dbid]) AS DatabaseName,
sql_text.text AS [Query Text],
query_stats.execution_count AS [Execution Count],
execution_plan.query_plan AS [Query Plan]
FROM sys.dm_exec_query_stats AS query_stats WITH (NOLOCK)
CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS sql_text
CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS execution_plan
WHERE
CAST(query_plan AS VARCHAR(MAX)) LIKE ('%CONVERT_IMPLICIT%')
AND
DB_NAME(sql_text.[dbid])='DB_NAME'
AND
CAST(query_plan AS VARCHAR(MAX)) NOT LIKE '%CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS sql_text%'
Başka makalede görüşmek dileğiyle..
Nefsini maddî ve mânevî kirlerden temizleyen kesinlikle kurtuluşa erecektir. (Şems suresi, 9. ayet)