本文翻译自SQLBI
在DAX中,变量除了可以增强DAX代码的可读性外,还可以优化DAX的性能。因为如何能够正确使用变量,能够减少多次计算同一个表达式。然而,在某些情况下,使用变量有可能适得其反,对性能产生负面影响。
首先,让我们介绍一下变量是如何改善代码的执行。例如,考虑下面的报表,计算销量的YTD,仅仅考虑在这两年中有销量的月份。

计算Sales YTDOY的代码如下:
Sales YTDOY :=CALCULATE (SUMX (VALUES ( 'Date'[Calendar Year Month Number] ),VAR CurrentSales = [Sales Amount]VAR PreviousSales = [Sales LY]RETURNIF (AND (CurrentSales <> 0,PreviousSales <> 0),CurrentSales - PreviousSales)),DATESYTD ( 'Date'[Date] ))
这个度量值在IF语句和减法运算中,在每个月仅仅计算一次计算Sales Amount 和 Sales LY 。这很好,另一种方法是更短的代码但是多次调用相同的度量值
Sales YTDOY slow :=CALCULATE (SUMX (VALUES ( 'Date'[Calendar Year Month Number] ),IF (AND ([Sales Amount] <> 0,[Sales LY] <> 0),[Sales Amount] - [Sales LY])),DATESYTD ( 'Date'[Date] ))
虽然DAX引擎在相同的筛选上下文中可能会重复利用同一度量值的计算结果,但是并总是如此。在这种情景下,变量是保证优化代码性能的好方法。
然而,变量是在他们各自的定义域内使用。如果一个变量是在条件语句之前定义的,那么不管条件如何,该变量都将被计算,此时,如果报表中有断开连接的筛选器,那么性能将会受到很大的影响。为了说明这个情况,考虑如下的报表,使用一个切片器控制矩阵表中的列是否展现的报表。该报表包含一个度量值:Sales,其上下文取决于切片器的选择。

可以使用变量定义度量值:
Sales vSlow =VAR PeriodSelection =SELECTEDVALUE ( 'Time Selection'[PeriodSelector] )VAR SalesAmount = [Sales Amount]VAR SalesLY = [Sales LY]VAR SalesYOY = [Sales YOY]VAR SalesYTD = [Sales YTD]VAR SalesLYTD = [Sales LYTD]VAR SalesYTDOY = [Sales YTDOY]RETURNSWITCH (PeriodSelection,"C", SalesAmount,"LY", SalesLY,"YOY", SalesYOY,"YTD", SalesYTD,"LYTD", SalesLYTD,"YTDOY", SalesYTDOY,BLANK ())
对于这个度量值,没有什么特别原因非要这样定义。因为每个变量只是使用一次。但是,可以在PeriodSelection的多个表达式中重用变量,从而减少数据模型中定义的度量。尽管如此,我们可能期望以下代码获得相同的性能:
Sales vFast =VAR PeriodSelection =SELECTEDVALUE ( 'Time Selection'[PeriodSelector] )RETURNSWITCH (PeriodSelection,"C", [Sales Amount],"LY", [Sales LY],"YOY", [Sales YOY],"YTD", [Sales YTD],"LYTD", [Sales LYTD],"YTDOY", [Sales YTDOY],BLANK ())
最后,我们在计算同一个条件语句:我们希望这个度量只有在使用时才计算,但是对IF和SWITCH函数的优化是值得的, 称为short-circut计算。它通过对IF和Switch的分支应用筛选器实现的。在vSlow度量值中,变量是在IF和Switch之前的同一定义域内定义的。因此,无论切片中选择了什么样的值,这些变量都会被计算一次。
这种行为的结果可能会严重影响结构良好的DAX的性能。因此,在使用变量时,最好遵循以下原则:
1. 当同一个DAX表达式在同一个筛选器上下文中多次计算时,将其赋值给一个变量,并引用该变量而不是
DAX表达式。
2. 当DAX表达式在IF或SWITCH的分支中求值时,无论什么时候,将表达式赋值给条件分支中的变量——这将保持shor-circut优化。
3. 如果变量只在条件分支中使用,则不要在IF或SWITCH语句之外定义变量。
4. IF和SWITCH的第一个参数可以使用在IF和SWITCH之前定义的变量,而不会影响性能
https://www.sqlbi.com/articles/optimizing-if-and-switch-expressions-using-variables/




