DAX Studio ile Performans Analizi

Power BI’da veri alımından görsel tasarıma kadar, her aşamada rapor performansını etkileyen pek çok faktör bulunur. Formüllerin optimizasyonu, bu unsurların en önemlilerinden biridir. DAX Studio gibi gelişmiş araçlar sayesinde formülleri detaylı bir şekilde analiz ederek, Power BI’ın tüm potansiyelinden en yüksek verimle yararlanabiliriz. Bu yazıda, ALLEXCEPT() ve SUMMARIZE() gibi yaygın olarak kullanılan DAX fonksiyonlarını karşılaştırarak, formül optimizasyonunda en iyi uygulamaları ve dikkat edilmesi gereken noktaları ele alacağız.

DAX Studio Nedir ve Neden Kullanılır?

DAX Studio, Power BI modellerini derinlemesine incelemek ve sorgu performansını optimize etmek için kullanılan ücretsiz bir araçtır. DAX sorgularının arka planındaki işlemleri adım adım gözlemleyerek, performans darboğazlarını tespit etmemize yardımcı olur. Buradan indirebilirsiniz: https://daxstudio.org/

Öncelikle belirtmek gerekir ki, DAX bir programlama dili değil, formül ve sorgu dilidir. Diğer bir deyişle formüllere ve sorgulara hangi sonucu istediğimizi belirtiyoruz ancak prosedürel bir yapısı olmadığı için hangi adımların nasıl gerçekleştiğini belirlemiyoruz. Bu da formüllerin ve sorguların arka planda nasıl davrandığını anlamamızı güçleştiriyor. İşte DAX Studio bu noktada, sorguların arka plandaki davranışlarını adım adım gözlemlememizi sağlayan bir araç olarak karşımıza çıkıyor.  Hem Formula Engine (formül motoru) hem de Storage Engine (depolama motoru) performansını analiz ederek, performans darboğazlarını tespit etmemize yardımcı oluyor.

DAX Studio’ya geçmeden önce, Power BI’da hangi motorun ne şekilde devreye girdiğini anlamakta fayda var. DAX sorguları iki ana motor kullanarak çalışır: Formula Engine (FE) ve Storage Engine (SE). Her iki motor da sorgu işleme sürecinin farklı aşamalarında görev alır.

Formula Engine (FE)

DAX sorgusunu alır ve bir sorgu planı oluşturur. FE, tablo birleştirme, filtreleme, toplam alma gibi işlemlerden sorumludur.  FE, tek iş parçacıklı bir yapıya sahiptir ve bu yüzden bir seferde sadece tek bir çekirdek kullanır. FE her işlem aşamasında SE’ye 1 sorgu gönderir, SE bu işlemi gerçekleştirmek için geçici bir depo oluşturur ve FE’ye döndürür. İşlem tamamlandığında ikinci FE sorgusuna geçilir. 

Storage Engine (SE)

ise verilerin fiziksel olarak saklandığı ve okunduğu katmandır. SE, iki ana yapı kullanarak çalışabilir: VertiPaq (bellekte veri tutma) ve DirectQuery (sorgu anında, veriyi doğrudan kaynaktan okuma.). VertiPaq, bellekte saklanan verileri hızla sunarken, DirectQuery verileri anında kaynaktan çeker. SE, FE’den gelen istekleri paralel olarak işleyebilir ve birden çok çekirdek kullanarak performansı artırır.

Sonuç olarak, her iki motoru da verimli kullanarak sorgu sürelerini optimize edebiliriz.

DAX Studio ile yapılan analizler sonucunda, ölçülerin SE ve FE aşamalarındaki performansı detaylı şekilde izlenebilir ve rapor performansını artırmak için hangi alanların optimize edilmesi gerektiği belirlenebilir. Bu bilgi, hem veri modelini hem de DAX formüllerini iyileştirerek Power BI raporlarının daha hızlı ve verimli çalışmasına yardımcı olacak önemli ip uçları içerir.

Örnek Senaryo:

Contoso örnek Power BI dosyası üzerinde,
tüm ülkeleri tarayarak hangi markaların hangi sınıf ürünlerden 100 Milyon Dolar üzerinde gelir getirdiğini listeleyecek üç formül oluşturalım ve formül performanslarını karşılaştıralım..

Power BI içerisinde aşağıdaki ölçüyü oluşturarak başlayalım:

Satış Döviz Tutarı = 

 SUMX(
    Sales, 
    Sales[SalesQuantity] * Sales[UnitPrice]
 )
 
 
 

Contoso’da BrandName ve ClassName kırılımında 100 Milyon Dolar üzerinde satış döviz tutarı olan satırların sonucunu hesaplamak istiyoruz. Bunun için iki ayrı formül kullanarak DAX Studio’da performanslarını kıyaslayalım. DAX Stüdyo’yu açalım ve Power BI modelini seçelim.

4 sütunlu bir tablo oluşturmak için SUMMARIZECOLUMNS() fonksiyonunu kullanalım. Tablomuz en yalın haliyle 

SUMMARIZECOLUMNS(Ülke, Marka, Sınıf, 100M üstü satışlar) .

Tablodaki Ülke, Marka, Sınıf kırılımının sonucunda 100 Milyon USD üzerinde satış tutarı elde eden satırları hesaplamak için ihtiyacımız olan formülü 3 farklı şekilde oluşturarak performanslarını test edelim. Her üç sorgunun sonucunda da şu tabloyu görmek istiyoruz:

DAX Stüdyo’da sorgular EVALUATE ile başlar ve default olarak tablo oluşturulması beklenir. Örneğin ALL(‘Product'[ClassName]) ya da VALUES(‘Product'[BrandName]) gibi. (EVALUATE öncesinde DEFINE() fonksiyonu kullanılarak ek tanımlamalar yapılabilse de bu yazıda bu konuya değinmeyeceğiz)

Bonus Tip: Eğer tablo değil de doğrudan bir ölçüyü değerlendirmek istersek, yine EVALUATE ile başlayarak altındaki formülü { } arasına yazarak çalıştırabiliriz.

İlk formülümüzde SUMMARIZE() fonksiyonunu CALCULATE() filtresi olarak kullanalım:

EVALUATE
    
VAR _100MUstuCalculateSummarize = 

    SUMMARIZECOLUMNS (
    	Geography[RegionCountryName],
        'Product'[BrandName],
        'Product'[ClassName],
        "_100M+",
            CALCULATE (
                [Satış Döviz Tutarı],
                
	                FILTER (
	                    SUMMARIZE (
	                        Sales,
	                        Geography[RegionCountryName],
	                        'Product'[BrandName],
	                        'Product'[ClassName]
	                    ),
	                    [Satış Döviz Tutarı] > POWER ( 10, 8 )
	                )
            )
    )
RETURN
    _100MUstuCalculateSummarize

Ekran görüntüsünde, ribbon’da mavi kare içinde görünen, Server Timings ve Clear on Run açalım. “Clear on Run” opsiyonu, sorgu her çalıştrırıldığında cache temizleyerek ölçüm yapmamızı sağlar. DAX Studio arayüzünde sol en üst kısımda yer alan RUN butonuna tıklayalım.  DAX Studio ekranının alt kısmında Server Timings sekmesine gelince ve FE sorgularının listesini, her adımın aldığı zamanı ve seçili FE adımında oluşan SQL sorgularını görebilirsiniz. İlk formülümüz FE 5 milisaniye, SE 293 milisaniye olmak üzere toplam 298 milisaniyede tamamlandı.

İkinci formülde SUMX ve SUMMARIZE() ile oluşturarak test edelim

EVALUATE
   
VAR _100MUstuSumX =
    SUMMARIZECOLUMNS (
    	Geography[RegionCountryName],
        'Product'[BrandName],
        'Product'[ClassName],
        "_100M+",
            SUMX (
                SUMMARIZE (
                    Sales,
                    Geography[RegionCountryName],
                    'Product'[BrandName],
                    'Product'[ClassName]
                ),
                IF (
                    [Satış Döviz Tutarı] > POWER ( 10, 8 ),
                    [Satış Döviz Tutarı]
                )
            )
    )
RETURN
    _100MUstuSumX

İkinci formülümüz FE 6 milisaniye, SE 66 milisaniye olmak üzere toplam 72 milisaniyede tamamlandı. 

3. formülde aynı ifadeyi CALCULATE() ve ALLEXCEPT() ile oluşturalım ve test sonuçlarını gözlemleyelim.

EVALUATE
    
VAR _100MUstuAllExcept = 

    SUMMARIZECOLUMNS (
    	Geography[RegionCountryName],
        'Product'[BrandName],
        'Product'[ClassName],
        "_100M+",
        	VAR Satis =
	            CALCULATE (
	                [Satış Döviz Tutarı],
	                ALLEXCEPT(
	                	Sales,
	                	Geography[RegionCountryName], 
	                	'Product'[BrandName], 
	                	'Product'[ClassName]
	                )
	            )
            RETURN IF(satis > POWER(10,8), satis)
     )
                
RETURN
    _100MUstuAllExcept
  • ALLEXCEPT() kullandığımız formülümüz FE 5 milisaniye, SE 17 milisaniye olmak üzere toplam 22 milisaniyede tamamlandı. Daha önce yazdığımız formülleri hatırlayalım.
  • İlk formülümüzde, SUMMARIZE() fonksiyonunu CALCULATE() filtresi olarak kullandığımızda, 298 ms.de tamamlanmıştı. 
  • İkinci formülümzde, SUMX tablo başvurusunu SUMMARIZE() ile oluşturarak test ettiğimizde, 72 ms.de tamamlanmıştı.

Kıyaslamamızın sonunda, senaryomuza göre ALLEXCEPT() ile yazdığımız formül daha hızlı çalışmaktadır diyebiliriz. DAX Studio Server Timings ile yapılan performans kıyaslamalarında, mümkün olan senaryolarda CALCULATE() ve modifiye eden  ALL(), ALLEXCEPT(), KEEPFILTERS() vb. fonksiyonlarıyla tanımlanmış örnekleri testlerinizde bulundurmanızı öneriyoruz. 

Burada küçük bir not ekleyelim. Contoso örnek modeller arasında görece büyük sayılsa da, Fact Table olan Sales Tablosunda yalnızca 2.2 milyon satır veri var. Daha büyük modellerde performans farkları daha büyük olacaktır. Örneğin daha büyük bir modelde ya da dizayn sorunu olan bir veri modelinde 0,4 sn, 1,4 sn ve 5,9 sn arasında seçim yapıyor olabilirdik.

Bu yazıda kullandığımız formülleri yalnızca performans ölçümünü simule etmek için oluşturduk. Farklı alternatif kodlar oluşturmak ya da yukarıdaki örneklere varyasyonlar oluşturmak mümkün. Örneğin _100MUstuCalculateSummarize formülündeki FILTER() fonksiyonu, tek başına kullanıldığında büyük veri setlerinde yavaş değerlendirmeye sebep olabilir. FILTER()’ dan önce  KEEPFILTERS() getirerek SE hesaplama süresini büyük ölçüde düşürebiliriz. Böylelikle CALCULATE() fonksiyonunun filtrelerin üstüne yazma özelliğini durdurarak filtreleri korumuş oluruz ve işlem süresi kısalır.

Sonuç olarak, Power BI performansını optimize etmek için hem Formula Engine (FE) hem de Storage Engine (SE) işleyişlerini anlamak büyük önem taşır. DAX Studio gibi araçlarla bu motorların nasıl çalıştığını analiz etmek ve sorgu performansını değerlendirmek, veri modellerinizi en verimli şekilde kullanmanıza olanak sağlar. Bu iki motorun doğru bir dengede çalışması, büyük veri setleriyle çalışırken bile yüksek performanslı raporlar oluşturmanızı sağlayacaktır. Unutmayın, küçük iyileştirmeler büyük performans kazançlarına dönüşebilir! DAX’la kalın..