
Bu makalede MSSQL Server Execution Plan Distribute Streams Operatörünü detaylı bir şekilde görmüş olacağız. Distribute Streams, Paralel çalışan Execution planlarda sık kullanılan operatörlerden olup bu operatör kendisine gelen bir kayıt kümesini birden fazla parçaya bölünüp işlemesi için kullanılan operatördür. Paralelizm genelde çok fazla kaynak gerektiren sorgular için SQL Server tarafından tercih edilir demiştik. Özellikle kayıt sayısı fazla olan tablolarımızda yaptığımız okuma işlemi sonucunda kayıtların işlenmesi için Distribute Streams kullanılarak okunan veri kümesi farklı parçalara bölünür. Burada dikkat edilmesi gereken nokta Distribute Streams tarafından verinin daha küçük veri kümelerine bölünmesi işlemi sırasında veri üzerinde değişiklik yapılmaz ve her kayıt farklı bir veri kümesinde olacak şekilde bölümleme işlemi gerçekleştirilir.
Tek bir girişten gelen satırları alır ve bunları yapılandırılmış olan “Degree of Parallelism” (DOP) ayarlarına göre birden fazla thread’e dağıtır. Veriyi thread’lere mümkün olduğunca eşit dağıtmaya çalışır ki bir çekirdek boş yatarken diğeri ter dökmesin.
Operatörün veriyi nasıl dağıtacağı, sorgunun mantığına göre değişir. Operatör özelliklerinde (Properties) şunları görebilirsiniz:
- Round Robin: Satırları sırayla 1, 2, 3, 1, 2, 3 şeklinde dağıtır. En basit ve hızlı dağıtım yöntemidir.
- Hash: Belirli bir kolonun değerine göre (örneğin CustomerID) hash hesaplar ve aynı değere sahip satırların her zaman aynı thread’e gitmesini sağlar. Özellikle Join ve Aggregate işlemlerinden önce önemlidir.
- Broadcast: Gelen tüm veriyi her bir thread’e kopyalar. Genellikle küçük tabloların büyük tablolarla joinlendiği durumlarda tercih edilir.
- Demand: Thread’ler işi bitirdikçe yeni satır talep eder.
Eğer Distribute Streams operatöründen sonra thread’ler arasında büyük bir veri eşitsizliği varsa (örneğin 1. thread 1 milyon satır işlerken 2. thread 10 satır işliyorsa), buna Parallelism Skew denir. Treadler arasındaki veri dağılımını görmek için properties ekranından bakılabilir. Actual Number of Rows kısmından görülebilir.
- Neden olur. Genellikle Hash dağıtımında kullanılan kolonun verilerinin düzensiz dağılmasından (Data Skew) kaynaklanır.
- Sonuç: Sorgu toplam süresi, en yavaş thread’in bitiş süresine takılı kalır.

Execution Plan’da operatörün üzerine gelip “Actual Number of Rows” kısmına baktığınızda, her thread’in kaç satır işlediğini görebilirsiniz. Eğer rakamlar arasında uçurum varsa, indekslerinizi veya istatistiklerinizi güncellemeniz gerekebilir.
Sorgularımız için Maxdop 1 kullanılırsa bu parametreyi göremeyiz.
Distribute Streams, SQL Server tarafından kullanıldığında veri kümemizin bölünmesi için kullanılan tüm işlemciler için aynı Session’ı kullanacaktır. Bu sebeple SQL Server’da açık olan bağlantıları incelediğimizde aynı Session id ile birden fazla defa karşılaşıyorsak bu ilgili Session için Paralelizm ve Distribute Streams operatörünün kullanıldığını göstermektedir.

Yukarıdaki görseli yorumlayacak olursak:
Görselin en altında yer alan Warnings kısmı en önemli noktadır. “Operator used tempdb to spill data during execution”. SQL Server, bu dağıtım işlemi için ayırdığı hafızanın (Memory Grant) yetmediğini fark etmiş. Bu yüzden veriyi RAM yerine çok daha yavaş olan diske (tempdb) yazıp oradan okumak zorunda kalmış. Bu durum sorgu performansını ciddi şekilde düşürür.
Partitioning Type (Hash): SQL Server veriyi rastgele değil, belirli bir kolona göre “karıştırarak” dağıtıyor. Diğer dağıtım yöntemleri Round Robin en basit dağıtım yöntemidir. Veri satırlarını sırayla (1. thread, 2. thread, 3. thread… ve tekrar başa dönerek) dağıtır. Veriyi işlemci çekirdekleri arasında olabildiğince eşit paylaştırmaktır. Belirli bir kolona göre gruplama (Join/Aggregate) gerekmediğinde, sadece iş yükünü bölmek için tercih edilir. Broadcast gelen verinin tamamını (tüm satırları) her bir paralel thread’e kopyalar. “Her kolda aynı veri olsun ki büyük tabloyla eşleşirken veri taşınmasına gerek kalmasın” mantığıyla çalışır. Genellikle çok küçük bir tablo (birkaç yüz satır) ile çok büyük bir tablo join edileceği zaman kullanılır. Küçük tabloyu her çekirdeğe kopyalamak, büyük tabloyu parçalara ayırıp taşımaktan daha az maliyetlidir. Demand (On-Demand) bu yöntemde dağıtıcı veri itmek yerine, boşta kalan thread’lerin veri talep etmesini bekler. Dinamik bir yük dengeleme sağlamaktır. Range Veriyi belirli bir değer aralığına göre böler (Örneğin: A-G arası 1. thread, H-Z arası 2. thread). Sıralı veri akışı sağlamaktadır.
| Tür | Veri Dağılım Mantığı | Temel Avantajı |
| Hash | Kolon değerinin özetine (hash) göre | Aynı değerlerin aynı kolda toplanması (Join/Group By için şart). |
| Round Robin | Sırayla, döngüsel | Mükemmel yük dengeleme (Hız). |
| Broadcast | Her kola verinin %100’ü | Küçük tablolar için join performansını artırır. |
| Range | Değer aralıklarına göre | Sıralı (sorted) veri setlerini korur. |
Partition Columns: Dağıtım için OwnerUserId kolonu kullanılmış. Yani aynı kullanıcı id’sine sahip satırlar aynı thread’e (iş parçacığına) gönderiliyor.
Output List: İşlem sonucunda OwnerUserId kolonu bir sonraki operatöre aktarılıyor.
Estimated vs Actual Rows: SQL Server 36.149.100 satır gelmesini beklerken (Estimated), gerçekte 3.130.328 satır gelmiş. Arada yaklaşık 11 katlık bir fark var. Bu, istatistiklerin güncel olmadığını veya SQL Server’ın yanlış bir tahmin yürüttüğünü gösterir. TempDB’ye taşma (spill) olmasının temel sebebi de muhtemelen bu yanlış tahmindir; SQL Server az veri beklediği için az RAM ayırmış, ama veri daha fazla gelince tıkanmış.
Number of Executions (4): Bu sorgu 4 paralel thread (çekirdek) üzerinde çalışıyor.
Estimated Operator Cost: Bu operatörün tüm sorgu içindeki maliyeti %28. Sadece veriyi dağıtmak için toplam eforun neredeyse üçte birinin harcanması oldukça yüksek bir maliyettir.
Ne yapılması gerekmektedir. Tahmin hatasını (36M vs 3M) gidermek için ilgili tablodaki istatistikleri UPDATE STATISTICS [Posts] komutuyla güncelleyebilirsin. Sorgunun daha fazla bellek kullanmasına izin vermek tempdb spill uyarısını ortadan kaldırabilir. OwnerUserId kolonu üzerinde uygun bir index olup olmadığını kontrol edebilirsin.
Bu makalede execution yapılarında görülen Distribute Streams ifadesine değinmiş olduk. Başka bir makalede görüşmek dileğiyle..
Onlar, namazı dosdoğru kılarlar ve kendilerine rızık olarak verdiklerimizden infak ederler. Enfal Suresi, 3. Ayet
