MSSQL Server Execution Plan Spool Kavramı

Bu makalede MSSQL Server Spool kavramlarını 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 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
  • Nonclustered 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.

Eager Spool

Eager Spool, Blocking operatör olup gerektiği durumlarda bir veri kümesindeki verilerinin tamamını bir defada okuyup sonuçlarını Tempdb veritabanında saklanmasını sağlamak için kullanılmaktadır. Eager Spool operatörünün veri kümesindeki kayıtların tamamını bir defada okuması doğrudan performansla ilgili değil veri bütünlüğü ile ilgili durumlarda da, veri bütünlüğünün sağlanması için de kullanılmaktadır.

Eager Spool bir önceki operatörden bir talep geldiğinde bütün satırları tek seferde alır ve tempb’ye atar. 

Özellikle Update işlemlerinde ortaya çıkabilecek olan Halloween Probleminin engellenmesi için Blocking operatör olan Eager Spool operatörü kullanılmaktadır.

SQL Server böyle bir sorun yaşamamak için güncelleme işlemi yapmadan önce verinin tümünü Spool işlemi ile okuyarak Tempdb veritabanında tutar ve tutmuş olduğu bu kayıtlar üzerinde sıra gözetmeksizin işlem yapar. Daha önce de değindiğimiz gibi SQL Server verinin tümünü bir defadan okuyup Tempdb veritabanında saklaması için Blocking operatör olan Eager Spool işlemini kullanacaktır.

Halloween senaryosunu yaşamasının en önemli sebebi veriyi bir temp tabloya almaması ve verinin tablo üzerinde güncellendikten sonra  ilgili kolun indexsli olduğu için kendi içerisinde tekrardan düzenlenir. Buda aynı kayıtların tekrar sıralanması ve en sonra değerlerin hepsinin eşit olacağını göstermektedir.

Ayrıca  yukarıdaki resimde dikkat etmemiz gereken bir diğer nokta ise Execution planımızda kullanılan Table Spool (Eager Spool) operatörünün üzerinde hem Table Spool hem de Eager Spool ifadesinin bulunmasıdır. Bunun sebebi ise her ikisi de Spool işlemi yapan Table Spool ve Eager Spool beraber kullanılabilen operatörlerdir. Çünkü Table Spool operatörü fiziksel bir operatör iken Eager Spool operatörü ise mantıksal (logical) operatördür. Fiziksel ve mantıksal operatörler arasındaki fark ise mantıksal operatörler yapılacak olan işlemi tanımlarken, fiziksel operatörler ise buna uygun olarak işlemi yapan operatörleri belirtmektedir. Yani Table Spool (Eager Spool) ile yapılacak mantıksal işlemin Eager Spool olduğunu görebiliyoruz. Eager Spool operatörü ile Nonclustered indeksimizden verinin bir defada tamamının okunacağını belirtiyoruz. Fakat verinin tamamının okunup Tempdb veritabanında bir tabloda saklanması işlemini fiziksel olarak yapan operatör ise Table Spool operatörüdür.

Lazy Spool

Lazy Spool Non-blocking operatör olup Eager Spool’dan farklı olarak kayıtların hepsini bir defada değil sadece ilgili operatör ihtiyaç duyduğunda teker teker okuyup yine geçici bir alanda saklayacaktır.

Lazy Spool bir önceki operatörden bir talep geldiğinde sadece o satırı alır ve tempdb’ye atar. (Nested Loop operatör’ünde satır satır okuma işlemi yapıldığı için görebilirsiniz.)

Execution planımızda birden fazla Spool operatörünün olması birden fazla veri kümesinin okunup Tempdb veritabanında tutulduğu anlamına gelmez. Çünkü Spool işleminin temel amacı bir veriye birden fazla defa erişme ihtiyacımızın olduğu durumlarda her defasında veri kaynağından bu veriyi okumak yerine bunun Spool işlemi ile depolanması ve ihtiyaç halinde kullanılmasıydı.

Yukarıdaki açıklamayı destekleyecek table spool’ların diğer spoolları referans aldığını görmüş olacağız. Yukarıdaki ilk table spool kavramının properties ekranına tıkladığımızda node id değerinin 2 olduğunu görmüş oluyoruz. Bu yapı aslında ilk lazy spool operatörüdür.

Şimdi diğer lazy spool operatör’e tıklayalım yukarıdaki Node ID değerini referans aldığını görmüş olacağız.

Yukarıdaki iki Primary Node ID değeri ilk oluşturulan lazy spool değerini tekrardan kullanmaktadır.

Nonclustered Index Spool

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. Nonclustered 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.

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

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

*Göklerde ve yerde ne varsa hepsi Allah’ındır. Allah’ın ilmi ve kudreti her şeyi kuşatmıştır. Nisa-126*

Author: Yunus YÜCEL

Bir yanıt yazın

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