In this post, I will show some samples on different ways to use filtering in DAX. If you write ineffective filters you will most likely always run into performance issues. We will also see the difference between using SUMMARIZE() and ROW() in queries that only return one row.
Let’s pretend one of your customers wants to know the sum of sales for the product “AWC Logo Cap”. And the minimum sales.
The benchmarking is done by running the different queries in DAX Studio multiple times. I have cleared the cache between the executions.
Sample query 1.
DEFINE MEASURE 'FactInternetSales'[MyFilteredNumber] = CALCULATE ( SUM ( FactInternetSales[UnitPrice] ), FILTER ( DimProduct, [EnglishProductName] = "AWC Logo Cap" ) ) MEASURE 'FactInternetSales'[MyFilteredNumberMin] = CALCULATE ( MIN ( FactInternetSales[UnitPrice] ), FILTER ( DimProduct, [EnglishProductName] = "AWC Logo Cap" ) ) EVALUATE ( FILTER ( SUMMARIZE ( FactInternetSales, DimProduct[EnglishProductName], "Filtered result", 'FactInternetSales'[MyFilteredNumber], "Filtered result min", 'FactInternetSales'[MyFilteredNumberMin] ), 'FactInternetSales'[MyFilteredNumber] > 0 ) )
This query produces the correct answer. But is does not perform very well.
It took 32 MS.
Then I will change my filters to not filter the entire table. Only the column that we are interested in.
This is done by using VALUES(..) on the column name in the filter expression.
Sample query 2.
DEFINE MEASURE 'FactInternetSales'[MyFilteredNumber] = CALCULATE ( SUM ( FactInternetSales[UnitPrice] ), FILTER ( VALUES ( DimProduct[EnglishProductName] ), [EnglishProductName] = "AWC Logo Cap" ) ) MEASURE 'FactInternetSales'[MyFilteredNumberMin] = CALCULATE ( MIN ( FactInternetSales[UnitPrice] ), FILTER ( VALUES ( DimProduct[EnglishProductName] ), [EnglishProductName] = "AWC Logo Cap" ) ) EVALUATE ( FILTER ( SUMMARIZE ( FactInternetSales, DimProduct[EnglishProductName], "Filtered result", 'FactInternetSales'[MyFilteredNumber], "Filtered result min", 'FactInternetSales'[MyFilteredNumberMin] ), 'FactInternetSales'[MyFilteredNumber] > 0 ) )
The query took now 25 MS to execute
What if I move the filter above SUMMARIZE()?
Sample query 3.
DEFINE MEASURE 'FactInternetSales'[MyFilteredNumber] = CALCULATE ( SUM ( FactInternetSales[UnitPrice] ) ) MEASURE 'FactInternetSales'[MyFilteredNumberMin] = CALCULATE ( MIN ( FactInternetSales[UnitPrice] ) ) EVALUATE ( FILTER ( SUMMARIZE ( FactInternetSales, DimProduct[EnglishProductName], "Filtered result", 'FactInternetSales'[MyFilteredNumber], "Filtered result min", 'FactInternetSales'[MyFilteredNumberMin] ), 'FactInternetSales'[MyFilteredNumber] > 0 && [EnglishProductName] = "AWC Logo Cap" ) )
The query went down to 13 MS
What if I re-write my query to use ROW() instead?
Sample query 4.
EVALUATE ( ROW ( "Filtered result", CALCULATE ( SUM ( FactInternetSales[UnitPrice] ), FILTER ( DimProduct, [EnglishProductName] = "AWC Logo Cap" ) ), "Count", CALCULATE ( MIN ( FactInternetSales[UnitPrice] ), FILTER ( DimProduct, [EnglishProductName] = "AWC Logo Cap" ) ) ) )
Then my query actually went down to 5 MS.
One last modification. Insert VALUES(..) to just apply the filter on the necessary column.
Sample query 5.
EVALUATE ( ROW ( "Filtered result", CALCULATE ( SUM ( FactInternetSales[UnitPrice] ), FILTER ( VALUES ( DimProduct[EnglishProductName] ), [EnglishProductName] = "AWC Logo Cap" ) ), "Count", CALCULATE ( MIN ( FactInternetSales[UnitPrice] ), FILTER ( VALUES ( DimProduct[EnglishProductName] ), [EnglishProductName] = "AWC Logo Cap" ) ) ) )
And now we went down to about 4 MS.
The server timings for “Sample query 1” looks like this
And the server timings for “Sample query 5” looks like this