MSSQL Server Execution Plan’da Index Spool Kavramı

Bu makalede MSSQL Server Spool kavramlarını sırasıyla detaylı bir şekilde ele almış olacağız. Spool kavramı sql server yapısında performansı arttırmak için kullanılan bir yapı olarak karşımıza çıkmaktadır. Genellikle execution plan yapılarında karmaşık olan işlemlerinde karşımıza çıkan bir yapıdır.

SQL Server’da Spool operatörleri, sorgu işlemcisinin (Query Processor) ara sonuçları geçici olarak saklayıp (genellikle tempdb üzerinde) tekrar kullandığı mekanizmalardır. Temel mantığı, “bir kez hesapla, defalarca kullan” prensibine dayanır.

Spooling genellikle performansı artırmak için kullanılır ancak bazen büyük veri setlerinde disk I/O yükü yaratarak darboğaz oluşturabilir.

Sql server yapısında bir veri okunduktan sonra tekrar kullanılma ihtimaline karşı okunan verinin Tempdb veritabanında tutulması işlemidir. Ekstra bir maliyet oluşmasın diye tabloya tekrardan ihtiyaç duyulma ihtimaline karşı geliştirilmiş olan bir yapıdır.

Birden fazla spool operatörü vardır. Bunlar:

  • Lazy Spool
  • Eager Spool
  • Table Spool
  • Row Count Spool
  • Index Spool

Genellikle spool operatörleri okuma yapan operatörlerle birlikte kullanılmaktadır.

Spool operatörlerinin veri okuması yapan operatörlerle beraber kullanıldığını söylemiştik. Fakat SQL Server’da Execution plan operatörleri başka bir operatör vasıtasıyla veriyi okurken iki yöntem kullanabilirler. Bunlardan ilki veri kümesinde bulunan kayıtlarımızın teker teker okunup işlenmesi işlemidir. Bu şekilde çalışan operatörlere Non Blocking operatörler denmektedir. Bu operatörlere örnek olarak Nested Loop Join operatörünü verebiliriz. Çünkü bildiğiniz gibi Nested Loop Join operatörü veri kümesi üzerinde her satır için işlem yapan bir operatördür.

İkinci bir veri okuma yöntemi ise veri kümesindeki verilerin teker teker değil tüm kayıtların aynı anda okunmasıdır. Bu şekilde çalışan operatörlere ise Blocking operatörleri denmektedir. En sık kullanılan Blocking operatörü ise Sort operatörüdür. Çünkü Sort yani sıralama işleminin yapılabilmesi için veri kümemizdeki kayıtların teker teker değil hepsinin beraber okunup değerlendirmesi gerekmektedir.

Şimdi execution plan üzerinde olan Index Spool operatörünü detaylı bir şekilde ele alalım:

Bu operatör de diğer Spool operatörleri gibi okunan verinin daha sonra kullanılmak üzere Tempdb veritabanında saklanmasını sağlamaktadır.  Fakat diğer operatörlerden farklı olarak tutmuş olduğu veri üstünde indeks oluşturup veriye sonraki erişimlerde bu indeks üzerinden erişim yapılmasını sağlamaktadır. Bunun en temel amacı ise Spool işlemi için kullanılacak veri boyutu büyük olduğunda ve bu veri kümesine eriştiğimizde herhangi bir koşul kullanmamız gerektiğinde tercih edilmesidir.

Eğer giriş verisi sıralı değilse veya bir Join işlemi için uygun bir index yoksa, SQL Server çalışma anında (on-the-fly) bir index oluşturarak sonraki erişimleri hızlandırır.

Index Spool operatörünün kullanıldığı Execution planlarımız için SQL Server’ın sorgu optimizasyonu için hem veriyi geçici olarak tutması hem de bu veri kümesi üzerinde indeks oluşturma ihtiyacı duyması hem sorgumuzu hem de indeks yapımızı kontrol etmemiz gerektiğini göstermektedir.

Index Spool (Eager Spool) operatörü ile verimiz üzerinde indeks oluşturularak TempDB veritabanında tutulmuştur. Bu işlemde Blocking operatör olan Eager Spool kullanılmasının sebebi ise tablomuzdaki tüm kayıtlar okunduktan sonra veri kümemiz üzerinde indeks oluşturulması gerekliliğidir. Çünkü indeks oluşturulmasının temel mantığı verinin fiziksel bir sırada tutulması olduğu için tüm veri kümesi okumadan bir sıralama yapmak mümkün olmayacaktır. Bu sebeple Index Spool (Eager Spool) operatörü tercih edilmiştir.

Query Optimizer tarafından Index Spool (Lazy Spool) operatörünün kullanılmasının amacı sorgu sonuçlarının tümünün aynı anda işlenmesi değil her satırın teker teker işlenmesinin daha performanslı olacağının düşünülmesidir. Daha açık bir ifadeyle Index Spool (Lazy Spool) operatörümüz her bir tarih verisi (OrderDate) için AVG(TotalDue) ifadesi ile ortalama hesaplayacaktır. Fakat bu ortalama hesaplama işleminin tablodaki tüm kayıtlar için yapılması gerekmemektedir. Çünkü tablomuzda OrderDate kolonunda tekrar eden çok fazla değer bulunmaktadır. Bu sebeple sürekli aynı değer için ortalama hesaplamak yerine sadece bir tanesi için hesaplamanın yapılıp ortalama bilgisinin Cache’e yazılması ve aynı olan diğer değerler için tekrar ortalama hesaplanması engellenmiş olacaktır.  Yukarıda anlattığımız gibi Query Optimizer aynı olan değerler için hesaplama yapmak yerine bu hesaplamayı bir defa yapıp sonucu Cache’e yazar ve aynı olan tüm değerler için tekrar hesaplama yapmadan bu değeri kullanır. Örneğin tablomuzda OrderDate değeri 2014-10-03 olan 100 tane kayıt olduğunu düşünelim. Bu değere ait ortalama hesaplama işleminin 100 kayıt için yapılmasından ziyade 1 kayıt için ortalama hesaplanmasının yapılıp Cache’de tutulması ve diğer kalan 99 tane kayıt için tekrar hesaplama yapılmadan Cache ‘deki bu değerin okunması daha performanslı olacaktır. Bu yapı birçok durumda Query Optimizer tarafından kullanılmaktadır. İşte bu sebeple Query Optimizer burada Index Spool (Lazy Spool) operatörünü seçmiştir. 

Index Spool (Lazy Spool) operatörümüzün Tooltip penceresinde gördüğümüz Actual Rebinds ve Actual Rewinds değerleri hesaplama işleminin yapıldığı birçok operatörde kullanılır. Bu değerlerin anlamı yukarıda bahsettiğimiz bir değer için hesaplama mı yapıldı yoksa değer Cache‘den mi okundu bunu göstermektedir. Yukarıdaki resimde gördüğümüz Actual Rebinds 1124 iken Actual Rewinds değeri ise 30341 olarak görünmektedir. Bunun anlamı Index Spool (Lazy Spool) operatörümüz 1124 farklı değer için hesaplama yapıp bu değeri Cache’e yazmıştır. Actual Rewinds değerinin 30341 olması ise hesaplanmış bir değerin 30341 defa Cache ‘den okunmuş olmasıdır. Daha açık bir ifadeyle toplamda 30341+1124 tane kayıt üzerinde işlem yaptık. Ve bu kayıt kümesi içinde işlem yaptığımız 1124 tane tekil değer mevcuttur.

Spool her zaman “kötü” değildir, ancak bazen eksik bir index’in habercisidir:

  • Tempdb Şişmesi: Spool işlemleri tempdb’de gerçekleşir. Eğer Spool operatörü milyonlarca satır işliyorsa, tempdb üzerinde ciddi bir yük ve yavaşlama oluşturur.
  • Index Eksikliği: Eğer planınızda sürekli Index Spool görüyorsanız, SQL Server size şunu demek istiyordur: “Burada bir index olsaydı ben bunu kendim oluşturmak zorunda kalmazdım.” Bu durumda ilgili kolonlara kalıcı bir index eklemeyi düşünmelisiniz. Index spool makalesi okunabilir.
  • Eager Spool ve Engelleme: Eager Spool, altındaki tüm veriyi okumadan üst tarafa veri göndermediği için sorgunun “ilk satırı getirme süresini” (Time to First Row) uzatabilir.

Bu, Spool türleri arasında en çok aksiyon gerektirenidir. SQL Server, “Sen index koymamışsın, ben çalışma anında (on-the-fly) geçici bir index oluşturuyorum” diyordur.

  • Aksiyon: Index Spool gördüğünüz kolonlar için kalıcı bir Index oluşturun. Bu, SQL Server’ı her sorgu çalıştığında sıfırdan index oluşturma yükünden kurtarır ve CPU kullanımını dramatik şekilde düşürür.
DurumGenellikle…Aksiyon Gerekli mi?
Index SpoolEksik Index belirtisidir.Evet, mutlaka index eklemeyi düşünün.
Büyük Verili Eager SpoolTempdb yükü ve yavaş başlangıç.Evet, sorgu mantığını veya Join’leri inceleyin.
Küçük Verili Lazy SpoolHafif bir optimizasyon.Hayır, genellikle zararsızdır.
Recursive CTE / Window Func.Mimari zorunluluk.Hayır, SQL Server’ın çalışma şekli budur.

Özetle Ne Yapmalısınız?

  1. Execution Count değerine bakın. Eğer Spool operatörü milyonlarca kez tetikleniyorsa, bu bir sorundur.
  2. Actual Number of Rows ile Estimated arasındaki farka bakın. İstatistikler güncel değilse SQL Server yanlışlıkla Spool kullanmaya karar vermiş olabilir. UPDATE STATISTICS komutunu deneyebilirsiniz.
  3. Tempdb üzerindeki PAGELATCH_IO gibi beklemeleri (waits) kontrol edin. Eğer Spool diske yazıyorsa, sistemi yavaşlatır.

Not: Row Count Spool Sadece satırların var olup olmadığını veya kaç adet olduğunu kontrol eder. Verinin kendisini değil, sadece sayısını veya varlık bilgisini saklar.

Bu makalede MSSQL Server Execution Plan Index Spool Kavramı detaylı bir şekilde görmüş olduk.

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

“Şüphesiz, Rabbin sana verecek ve sen de hoşnut olacaksın.”. Duha Süresi-5 Ayet

Author: Yunus YÜCEL

Bir yanıt yazın

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