Execution Plan Okuma Rehberi

SQL Server Management Studio'da execution plan'ların nasıl okunacağı, pahalı operatörlerin belirlenmesi ve sorgu optimizasyonu adımları anlatılır.

Execution Plan Okuma Rehberi

Execution Plan Okuma Rehberi: Yavaş Çalışan SQL Sorgularını Tespit Etme

Bir sorgu yavaş çalıştığında, ilk yapmanız gereken şey Execution Plan (Yürütme Planı)'nı incelemektir. Execution plan, SQL Server'ın sorgunuzu çalıştırmak için izlediği yol haritasıdır. Hangi tablolara hangi sırayla erişildiğini, hangi index'lerin kullanıldığını, hangi operatörlerin ne kadar maliyetli olduğunu ve verilerin nasıl birleştirildiğini (join) gösterir. Bu yazıda, SQL Server Management Studio (SSMS) üzerinden execution plan'ları nasıl okuyacağınızı, en pahalı operatörleri nasıl tespit edeceğinizi ve sorgularınızı nasıl optimize edeceğinizi adım adım ele alacağız.


1. Execution Plan Türleri

  • Estimated Execution Plan (Tahmini Yürütme Planı): Sorgu çalıştırılmadan önce SQL Server'ın istatistiklere (statistics) dayanarak oluşturduğu plandır. Hızlıdır ancak gerçek çalışma zamanı maliyetlerini (I/O, CPU, memory) yansıtmaz.

  • Actual Execution Plan (Gerçek Yürütme Planı): Sorgu çalıştırıldıktan sonra, gerçek çalışma istatistikleriyle birlikte elde edilen plandır. En doğru ve kullanışlı olanıdır. SSMS'de Include Actual Execution Plan (Ctrl+M) seçeneği ile aktifleştirilir.


2. Execution Plan Nasıl Okunur? (Akış Yönü)

Execution plan, sağdan sola ve yukarıdan aşağıya doğru okunur. Planın en sağındaki operatör, sorgunun ilk adımını (verinin okunduğu tablo veya index) temsil eder. Sola doğru ilerledikçe, veriler birleştirilir (join), filtrelenir (filter), sıralanır (sort) ve son olarak sorgu sonucu (SELECT) ekrana gelir.


3. Operatör Maliyetlerini Anlama

Her operatör, toplam maliyetin yüzdesel olarak ne kadarını tükettiğini gösterir. Bu yüzde, operatörün üzerine geldiğinizde tooltip'te veya özellikler (properties) penceresinde görünür.

  • Cost (Maliyet): SQL Server'ın bir operatörü çalıştırmak için tahmin ettiği kaynak maliyetidir (I/O + CPU). %100'e kadar toplanır.

  • Subtree Cost (Alt Ağaç Maliyeti): O operatör ve altındaki tüm operatörlerin toplam maliyetidir. Bir operatörün Subtree Cost'u yüksekse, o operatör ve altındaki tüm işlemler optimize edilmelidir.

Püf Noktası: En yüksek maliyetli operatörü bulmak için plana bakın. İlk olarak en yüksek yüzdeye sahip operatörü optimize etmeye çalışın. Genellikle bu bir Table Scan, Clustered Index Scan veya Key Lookup'tur.


4. En Yaygın (ve Pahalı) Operatörler ve Çözümleri

Operatör Açıklama Performans Etkisi Çözüm / Optimizasyon
Table Scan Tablonun tamamı taranır. Index yok veya kullanılamıyor. 🚨 Çok Yüksek (Tüm veri okunur) Tabloya uygun bir index ekleyin (WHERE veya JOIN sütunlarına).
Clustered Index Scan Clustered index'in tamamı taranır (aslında Table Scan ile aynıdır, ancak clustered index üzerinde). 🚨 Çok Yüksek Sorguyu daraltacak bir non-clustered index oluşturun veya mevcut index'i kapsayıcı (covering) hale getirin.
Index Scan Non-clustered index'in tamamı taranır. 🟡 Orta-Yüksek Daha dar bir sorgu yazın veya index'i filtreli (filtered) hale getirin.
Index Seek Index üzerinde doğrudan arama yapar. 🟢 Düşük (İdeal) Zaten doğru index kullanılıyor.
Key Lookup (Bookmark Lookup) Non-clustered index'te bulunan satır bulucu (pointer) ile veri sayfasına gidilir ve sorguda istenen diğer sütunlar alınır. 🟡 Orta-Yüksek (Her satır için ek I/O) Covering Index oluşturun: INCLUDE ile sorgudaki tüm sütunları index'e ekleyin.
Hash Match (Join) İki tabloyu birleştirmek için hash tablosu kullanır. Genellikle index'siz join'lerde veya büyük tablolarda görülür. 🟡 Orta-Yüksek Join sütunlarına index ekleyin veya sorguyu yeniden yazın.
Nested Loops (Join) İç içe döngü ile iki tabloyu birleştirir. Küçük tablo + index'li büyük tablo için idealdir. 🟢 Düşük (Eğer doğru index varsa) Zaten iyi, ancak iç tabloda arama yapmak için index olduğundan emin olun.
Sort Verileri ORDER BY veya GROUP BY için sıralar. Büyük veri kümelerinde maliyetli olabilir. 🟡 Orta Sıralama işlemini index üzerinden karşılamaya çalışın. ORDER BY sütununu index anahtarının sonuna ekleyin.
RID Lookup Heap tablosunda (clustered index'siz) satır bulucu (RID) ile veri sayfasına gidilir. 🟡 Orta Tabloyu clustered index'li hale getirin veya covering index oluşturun.

5. Execution Plan'da Dikkat Edilmesi Gereken Uyarılar

  • Missing Index Hints (Eksik Index Önerileri): SSMS, planın üst kısmında yeşil bir metinle "Missing Index" önerisi sunabilir. Bu öneriler genellikle doğru ve faydalıdır, ancak her öneriyi uygulamak doğru olmayabilir. Özellikle çok sayıda yazma işlemi olan tablolarda dikkatli olun.

  • Warning (Uyarı) Simgeleri: Plan üzerinde sarı üçgen veya kırmızı daire şeklinde uyarı simgeleri olabilir. Bunların üzerine gelerek hangi sorunun yaşandığını öğrenin (ör. CONVERT_IMPLICIT - veri tipi dönüşümü, NO JOIN PREDICATE - join koşulu eksik).

  • Data Type Conversion (Veri Tipi Dönüşümü): WHERE koşulunda veya JOIN sütununda veri tipi uyuşmazlığı varsa (ör. VARCHAR ile NVARCHAR karşılaştırması), SQL Server bu sütundaki index'i kullanamaz ve Table Scan yapar. Plan'da CONVERT_IMPLICIT operatörünü arayın.


6. Execution Plan Analizine Kullanılabilecek Araçlar

  • SQL Server Management Studio (SSMS): En temel ve en güçlü araçtır. Planı grafiksel olarak gösterir.

  • Database Engine Tuning Advisor (DTA): SSMS içinde bulunan bu araç, execution plan'ı analiz ederek size index, istatistik veya bölümlendirme (partitioning) önerilerinde bulunabilir.

  • Query Store: SQL Server 2016+ ile gelen bu özellik, sorgu performansını tarihsel olarak takip eder, plan değişikliklerini izler ve geri plan döndürme (force plan) olanağı sunar.

  • Azure Data Studio: SSMS'in hafif, cross-platform alternatifidir. Execution plan görselleştirmesi sunar (ancak SSMS kadar detaylı değildir).


7. Gerçek Dünya Örnek Analizi

Yavaş Sorgu: "20.000 adet ürünü olan bir e-ticaret sitesinde, 1 Ocak 2023 ile 31 Aralık 2023 arasındaki siparişleri getiren sorgu 5 saniye sürüyor."

Execution Plan İncelemesi:

  1. Actual Execution Plan alınır.

  2. Planın sağında bir Clustered Index Scan (veya Table Scan) operatörü görülür, maliyeti %70'tir.

  3. Operatörün üzerine gelindiğinde, Orders tablosunun tüm satırlarını okuduğu görülür (Estimated Rows: 1 Milyon).

  4. WHERE koşulunda OrderDate sütunu kullanılıyor, ancak bu sütunda index yok.

Optimizasyon Adımları:

  1. OrderDate sütununa non-clustered index oluşturulur.

  2. Plan tekrar alındığında, Clustered Index Scan yerine Index Seek (Non-Clustered) operatörü gelir.

  3. Ancak şimdi de Key Lookup operatörü belirir (%40 maliyetle).

  4. Sorgu SELECT OrderId, CustomerName, OrderDate, TotalAmount gibi sütunlar getiriyor.

  5. Key Lookup'u ortadan kaldırmak için INCLUDE ile covering index oluşturulur:

    sql

    CREATE NONCLUSTERED INDEX IX_Orders_OrderDate 
    ON Orders (OrderDate) 
    INCLUDE (OrderId, CustomerName, TotalAmount);
  6. Plan tekrar alındığında, artık sadece Index Seek (non-clustered) operatörü kalır ve toplam maliyet %5'in altına düşer. Sorgu 50 ms'de tamamlanır.


8. .NET / EF Core ile Execution Plan Analizi

EF Core, SQL Server ile çalışırken yavaş sorguları tespit etmenin birkaç yolu vardır:

  • Logging (Günlük Kaydı): EF Core, sorguları ve bunların execution plan'larını loglayabilir. optionsBuilder.LogTo(Console.WriteLine) ile tüm SQL sorgularını ve execution plan'larını konsola yazdırabilirsiniz.

  • ToQueryString(): Bir LINQ sorgusunun hangi SQL'e dönüşeceğini görmek için .ToQueryString() metodu kullanılabilir. Bu SQL'i SSMS'de çalıştırarak execution plan'ını inceleyin.

  • FromSqlRaw / FromSqlInterpolated: Ham SQL sorguları yazarken, bu sorguları da execution plan ile test edin.

  • Application Insights veya SQL Server Profiler: Production ortamında, yavaş sorguları tespit etmek ve execution plan'larını yakalamak için SQL Server Profiler veya Azure Application Insights kullanılabilir.

Sonuç:

Execution Plan okuma becerisi, bir veritabanı veya .NET geliştiricisinin en değerli yeteneklerinden biridir. Sorgu performansının nasıl optimize edileceğine dair en doğru kararları, plan'ı okuyarak verebilirsiniz. Unutmayın:

  • Sağdan sola okuyun.

  • En pahalı operatör en soldaki değil, en yüksek yüzdeye sahip olanıdır.

  • Key Lookup ve Table Scan en büyük düşmanlarınızdır. (Covering index ile çözülür.)

  • İstatistikler (Statistics) güncel değilse, SQL Server yanlış plan seçebilir. Düzenli olarak istatistik güncellemesi yapın.

  • Her zaman Actual Execution Plan ile çalışın.

Tüm yazılar