MSSQL Server Execution Plan Yorumlanması

Bu makalede execution plan incelenirken nelere dikkat edilmesi gerektiğini ele almış olacağız. Önceki execution plan makalemizde Estimated ve Actual Execution kavramlarından bahsetmiştik. Bu plan yapılarını inceleyerek nasıl aksiyon almamız gerektiğinden bahsedelim.

Grafiksel Execution plan yapılarında okuma işlemi sağdan sola ve yukarıdan aşağıya doğru yapılmaktadır. Execution plan yapılarında karşılan bir başka ifade ilgili ikonun altında hangi tablo üzerinde hangi index yapısının kullanıldığı ve Cost bölümünde ilgili ifadenin sorguda maliyeti gösterilmektedir. Aşağıdaki ekran resminde Select ikonu üzerinde %0 yazması o işleme hiç zaman ayrılmadığı anlamına gelmemektedir. Sadece tüm zaman hesaplanıp iki ikona oranlandığında Select işlemi için sıfıra yakın bir değer çıktığı için değer sıfır olarak gösterilmektedir.

Yukarıdaki ifadede select ikonu en fazla karşılaşacağımız ikonlardan biri olarak karşımıza çıkmaktadır. Genellikle gözardı edilmesi gerekmektedir. Şimdi select ikonun Tooltip penceresini inceleyelim. İlgili ikon üzerine faremizle geldiğinde çıkmaktadır.

Cached Plan Size: Execution planımız Cache’de ne kadar yer kaplayacağını belirtmektedir.

Estimated Operator Cost: Daha önceden incelediğimiz ikonların üzerinde yazan ve bu işlemin toplam işlem içindeki yüzdelik maliyetini belirten değerdir.

Estimated Subtree Cost: Select ifadesinden  önceki adımlarda toplam harcadığı zamanı göstermektedir.

Degree of Parallelism:  Sorgumuzda paralelliğin dinamik olarak kullanıldığını söylemektedir. Manuel bir değer set edilmemiştir.

Estimated Number of Rows for All Executions: Bu ifade istatistiklere bakarak 0 satır döneceği anlamına gelmektedir. Yukarıdaki sorgu çalıştığında büyük satır gelmeyeceğini görmüş olacağız.

Estimated Number of Rows: Bu operatörün çalışmasıyla kaç satırın  etkilendiği veya kaç kayıt üzerinde işlem yapıldığını göstermektedir.

Statment: Bu kısmında ise hangi sorguyu çalıştırmışsak o sorgu görülmektedir.

Select sorgusundan önceki  Clustered Index Scan  ikonunun üzerine gelip Tooltip penceresini inceleyelim.

Yukarıdaki resimlerde bulunan Tooltip pencerelerini farklı olması her sql server execution plan operatörünün kendine has verileri özetlemesidir.

Şimdi yukarıdaki Clustered Index Scan Tooltip penceresini inceleyelim.

Physical Operation: Sorgu çalıştırıldığında yapılacak olan işlemi temsil eder. Actual Execution plan yapısını temsil etmektedir.

Logical Operation: Sorgu çalıştırılmadan tahmin edilen işlemi göstermektedir. Estimated Execution plan yapısını temsil etmektedir.

Genellikle yukarıdaki iki ifade birbirine eşit çıkmaktadır.

Execution Mode: Bu kısımda optimizer tarafından hangi execution modu kullanacağına karar verilir. Bunlar yukarıda belirtilen  Actuel Execution Mode  ve Estimated Execution Mode  olmak üzeridir. Bu kavramların karşısında Row ve BatchMode ifadeleri yer almaktadır. Row mode, satır satır işlem gerçekleştirirken BatchMode belli bir gurup satır üzerinden işlem gerçekleştirir.

Batch mode bazı işlemleri desteklemektedir(scan,filter, hash vb.). Query Optimizer eğer çok büyük veriler üzerinde gruplama, birleştirme gibi işlemler gerçekleştirecekse Batch Mode’u tercih eder(tabi columstore’a yönelik indexleriniz varsa) bunun dışındaki senaryolarda Row Mode’u tercih eder.

Storage: İşlemin gerçekleşeceği storage(In-Memory) belirler RowStore veya ColumStore. Tabi bu yine execution mode’a göre belirlenmektedir. Row mode ise RowStore, batch mode ise ColumsStore üzerinde çalışacaktır.

Number of Rows Read: Okunan satır sayısını belirtmektedir.

Actual Number of Rows/Batches: İlgili işlemin gerçekleşmesi için okunan satır/batch sayısı.

Peki Estimated number of rows to be read ile Actual Number of rows read arasındaki farkı örnek üzerinden konuşursak daha net anlaşılır. İki farklı işlemimiz var bir tanesi index scan yapıyor koşulumuz ise Id ve Status bazlı olsun scan işleminde 1000 satır olan tabloda koşula uyanları bulması için 1000 satırı da okumak zorunda( estimated number of rows read) sonuç olarak ise bu 1000 satır içerisinden 300 satırı(actual number of rows) dönüyor.

Bir diğer işlemimizde ise index seek yapıyor sorgumuzun parametrelerine göre indexlenmiş tabloda direk doğru kayıtları okuduğundan dolayı her iki değerde 300’ü göstermektedir.

Estimated I/O Cost:  Yapılan işlem için  I/O maliyetini belirtmektedir.

Estimated Operator Cost: Yapılan işlem için harcanan toplam süreyi ve yüzdesini belirtmektedir.

Estimated CPU Cost: Yapılan işlem için CPU maliyetini belirtmektedir.

Estimated Subtree Cost: İlgili adıma gelen kadar geçen süreyi belirtmektedir. Dikkat ederseniz okuma sağdan sola olduğu için Estimated Operator Cost ve Estimated Subtree Cost  maliyetleri aynıdır.

Estimated Number of Rows: İlgili işlem sonucu  kaç kaydın etkilendiğini göstermektedir.

Estimated Row Size: Her bir kaydın kapladığı alanı göstermektedir.

Actuel Rebinds ve Actuel  Rewinds:  İlgili işlemin kaç kere yapıldığını göstermektedir. Genellikle döngüsel ifadelerde bu değerler yüksek olabilmektedir.

Ordered: Veri kümesinin sıralı olup olmadığını göstermektedir. False değeri sıralı olmadığını göstermektedir. Eğer sorgumuzda order by ifadesini kullanmış olsaydık bu değer true olarak gösterilmiş olurdu.

NodeID: Exection Plan yapılarında ilgili execution ikonunun seviyesini belirtmektedir. Numaralandırma yapılırken soldan sağa doğru yapılmasına karşılık, Execution planlar yorumlanırken sağdan sola doğru okuma yapılır.

Object: Bu bölümde ilgili tooltip işlemi için  hangi veritabanı tablosunu ve index kullanıldığını görebiliriz.

Output List: İlgili operatörün  sonucunda  dönen sonuç kümesini göstermektedir.

Predicate, bir sorgunun WHERE, JOIN veya HAVING gibi filtreleme koşullarını ifade eder. Execution plan’da, veri satırlarının hangi kriterlere göre filtrelendiğini gösterir. Filtreleme İşlemi: Predicate, hangi satırların işleme alınacağını belirler. Predicate’lerin nasıl uygulandığı, sorgu performansını doğrudan etkiler. Predicate’lerin index’lerle uyumluluğu, index kullanım verimliliğini belirler. CONVERT_IMPLICIT ile dönüştürme işlemi yapılıyor. Daha sonra filtreleme işlemi olmaktadır. Bizim için kritik bir öneme sahiptir.

Outer References (Dış Referanslar), bir JOIN işlemi veya alt sorgu (subquery) çalıştırılırken, dış sorgudan (outer query) iç sorguya (inner query) aktarılan değerleri ifade eder. HumanResources.Employee tablosundaki BusinessEntryID sütununun dış referans olarak kullanıldığını göstermektedir. Nested Loops Join’de: Dış tablodan (outer table) alınan her satır için iç tablo (inner table) taranırken bu değerler kullanılır.

Expr1008, SQL Server execution planlarında otomatik olarak oluşturulan geçici ifadeleri (expression) temsil eder. Bu tür ifadeler genellikle sorgu işleme sırasında oluşturulan ara değerleri veya hesaplamaları gösterir.

Otomatik Oluşturulan İfadeler

– SQL Server’ın sorguyu işlerken oluşturduğu geçici sütunlar veya hesaplanmış değerler.
– “Expr” kısaltması “Expression” (ifade) anlamına gelir.
– Numara (1008) ise bu ifadenin benzersiz tanımlayıcısıdır.

Ne Zaman Görünür

– Sorguda açıkça sütun adı verilmeyen hesaplamalar yapıldığında
– Satır filtreleme veya sıralama işlemlerinde
– JOIN koşullarında karmaşık ifadeler kullanıldığında
– GROUP BY veya WINDOW fonksiyonları kullanıldığında

Residual (Artık/Kalıntı Koşul), SQL Server execution plan’larında özellikle JOIN işlemleri sırasında karşılaşılan önemli bir performans kavramıdır.

Residual, bir JOIN işlemi sırasında:
– JOIN koşulunun tamamını karşılayamayan ek filtreleme koşullarını
– JOIN’den sonra uygulanması gereken artık kontrol koşullarını
– Index’lerle tam olarak karşılanamayan ek karşılaştırma işlemlerini ifade eder.

Neden Oluşur?

1. Birden fazla sütunun JOIN’de kullanılması
2. JOIN yapılan sütunların veri tiplerinin farklı olması
3. JOIN koşulunda fonksiyon kullanılması (CONVERT, CAST vb.)
4. JOIN sütunlarında uygun indexlerin bulunmaması

Bu ifadenin önüne geçmek için sorgunun yeniden yazılması, istatistiklerin güncellenmesi, composite index oluşturulması veya veri tiplerinin uyumlu hale getirilmesi gerekmektedir.

Hash Keys Probe kısmı ise Hash işleminde kullanılacak olan değeri belirtmektedir.

Build Residual”, SQL Server execution plan’larında özellikle hash join kullanıldığında karşımıza çıkan bir kavramdır.

Build Residual, SQL Server’ın hash join sırasında:
• Join predicate’in (birleştirme koşulunun) tamamını hashing sırasında değerlendirememesi,
• Bu yüzden ekstra bir filtreleme adımı yapması gerektiği anlamına gelir.

Bir başka operatör ise Bitmap operatörüdür.

Bu operatör, SQL Server’ın büyük veri kümelerinde daha hızlı filtreleme yapmak için geçici bir bitmap indeks oluşturduğunu gösterir. Özellikle:

1. Ne Yapar?
– Verilerden bir “bit haritası” (1 ve 0’lardan oluşan bir filtre) oluşturur
– Bu bitmap, hangi satırların sorgu koşulunu sağladığını işaretler
– Sonraki operatörler bu bitmap’i kullanarak gereksiz veri okumalarını önler

2.Neden Kullanılır?
– Büyük tablolarda JOIN, WHERE veya HAVING işlemlerini hızlandırmak için
– Özellikle IN veya EXISTS gibi koşullarda performans sağlar
– Fiziksel veri okuma maliyetini azaltır

3. Cost: 0% Ne Demek?
– Bu işlemin toplam sorgu maliyetine neredeyse hiç katkısı olmadığını gösterir
– Çok verimli bir optimizasyon olduğuna işaret eder

Gerçek Hayattaki Benzetme:
Bir kütüphanede tüm kitapları tek tek okumak yerine, sadece ilgili bölümlerin numaralarını bir kağıda yazıp diğer aramaları bu liste üzerinden yapmaya benzer.

Bu operatör genellikle sorgu performansını arttıran bir iyileştirme işaretidir.

Tooltip penceresi sizin ihtiyaçlarınıza cevap vermiyorsa daha detaylı bir şekilde operatörün üzerine sağ tıklayıp Properties ekranından görebiliriz.

Şimdi Clustered Index Scan operatörünün üzerine sağ tıklayıp properties penceresinden inceleyelim.

Aşağıdaki ekran karşımıza çıkmaktadır.

Yukarıdaki ekran resminde Tooltip penceresinde olmayan  Forced IndexForceScanDefined ValuesNoExpandHint kavramları karşımıza çıkmaktadır.

Defined values: İşleme eklenecek olan bilgileri göstermektedir. Bir nevi Output List ifadesinin çıktısıdır. Sorgu sonucunda dönecek sonuç kümesini göstermektedir.

Forced Index: Sorgumuzu çalıştırması için herhangi bir indeksi kullanmaya zorlayıp zorlamadığımız bilgisini verir. Sql server doğru index yapısını seçemediği için kullanıcının sorgusunda manuel olarak index kullanımına zorlanması sağlanacaktır. Örnek vermek gerekirse aşağıdaki select sorgumuzda belirtilen index yapısını kullanmaya zorluyoruz.

select*from Person.Address with(index([PK_Address_AddressID]))

Yukarıdaki index yapısını sorgumuza zorladığımızda Forced Index değerinin true olduğunu görmüş oluyoruz.

NoExpandHint: Forced Index ifadesi ile benzer işleve sahip olup Indexed View’lar üzerinde kullanılmaktadır.

Output List kısmında sorgu sonucunda getirilecek kolunlar belirtilmektedir.

Grafiksel Execution plan yapısını yorumlayabilmek için öncelikle 80’yakın operatörün ne işe yaradığını bilmek gerekmektedir. İlerleyen makalelerimizde detaylı bir şekilde bu operatörleri görmüş olacağız.

Yukarıdaki ifademizde select ikonunun üzerindeki ünlem işaretine değinecek olursak. The query memory grant detected ‘ExcessiveGrant’, which may impact the reliability. Hatası ile karşılaşırız. Bu uyarının anlamı: SQL Server, sorgunun çalışması için bellek (Memory Grant) ayırıyor. Ancak burada sorguya normalden fazla bellek ayrıldığı ve bunun sistem performansını olumsuz etkileyebileceği belirtiliyor.

Detaylar:
• Memory Grant (İstenen): Initial 103032 KB
• Gerçek Kullanılan: Used 39004 KB

Bu, SQL Server’ın sorgu için yaklaşık 103 MB bellek ayırdığını, ama sadece ~39 MB’lık kısmını kullandığını gösteriyor.

Bu duruma “Excessive Grant” deniyor çünkü:
• Gereksiz yere fazla bellek rezerve ediliyor.
• Bu durum yoğun sistemlerde başka sorguların yavaşlamasına veya sıraya girmesine sebep olabilir.

Bazen sorgularımızın execution planında CONVERT(VARCHAR(15), k.KLNADI, 0) ifadesinin sorgunun execution planını değiştirdiğini görürüz. Bu gibi durumlarda index eksikliği, sıralama işleminin büyük veri kümesi üzerinde yapılması veya select ifadesinde tüm verinin belleğe taşınması olabilir. k.KLNADI sütunu VARCHAR(15) tipine dönüştürülüyor. 0 parametresi varsayılan dönüşüm stilini belirtiyor. Herhangi bir önemi yok belirtilmese de olur. Bu yapılar index kullanımını engellemektedir. Tablonun taranmasına sebep olmaktadır.

Sorgularımızda bazen sorgularımız bir temp tabloya açılır bu tablo üzerinde sıralama işlemi yapılmaktadır.

  select * into #temp from [AdventureWorks2012].[dbo].[Table_1]
  select*from #temp order by kolon1 desc

Başka bir makalede görüşmek dileğiyle..

“Yavrucuğum, namazını özenle kıl, iyi olanı emret, kötü olana karşı koy, başına gelene sabret. İşte bunlar, kararlılık gerektiren işlerdendir.”Lokman-17

Author: Yunus YÜCEL

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir