美文网首页
DAX连接表系列(四) ⅤAR変量(7)

DAX连接表系列(四) ⅤAR変量(7)

作者: PowerBI非官方 | 来源:发表于2018-06-21 17:19 被阅读0次

    优化互斥计算

            本内容基于SQLBI官方文献整理的简体笔记 -- Power 零售 BI

          本文介绍如何使用优化:可能会导致查询性能下降的互斥(相互排斥)计算的DAX表达式 。
          在以前的文章中,我们讨论了变量的重要性以及如何运用其优化IF函数模式,以减少对同一表达式或度量的多次计算。 但是,有些情况下,在同一表达式的不同定义分支中(比如由IF定义的多个条件结果)执行的计算似乎很难被优化。 例如,请考虑以下模式:

    Amount := IF (<Condition>, [Credit],  [Debit])-- 如果符合条件,则计算[Credit],否则计算[Debit]。

          这种涉及到度量A和B的情况,似乎没有任何可能的优化。 然而,通过考虑两个度量A和B各自的性质:它们可能是基于某个相同基本度量的计算,只不过针对该度量定义了不同的筛选条件参数而产生不同的计算。 例如,度量A和B可以定义为:

    Raw Amount :=SUM ( Transactions[Line Amount] )
    Credit := CALCULATE (  [Raw Amount], Transactions[Type] = "Credit")
    Debit : = CALCULATE ( [Raw Amount], Transactions[Type] = "Debit")

          在这种情况下,DAX可能会生成一个查询计划,其中这两种新度量均在内部进行计算,即使在报表中实际上仅显示其中的某一个度量(基于同一度量定义的不同度量)。例如,通过应用筛选来确定对IF条件的持续计算声明。
            当然,在一般的简单表达式中,DAX可能会应用short-circuit  --直接短路式计算,从而跳过不必要的任何分支的计算。 但是,在复杂报表中,为了生成批量计算的高效查询计划,此优化通常不可用。
            那么,怎样才能优化相类似的这种表达呢?

          我们知道,编写DAX代码时的一个经验法则是:
          先定义筛选器以筛选出计算列表,然后执行CALCULATE计算,这比针对不同的条件而编写不同的CALCULATE语句要更方便。 因此,以前的代码可以写成如下:

    Raw Amount :=SUM ( Transactions[Line Amount] )
    Amount := VAR TransactionType = IF ( <condition>,"Credit",  "Debit"  )
    RETURN
    CALCULATE (  [Raw Amount], Transactions[Type] = TransactionType  )

          虽然,在这样一个简单的例子中,这种编码可能不会转化为性能优势,但在一些复杂表达中,该方法可能会更快。 可以通过测试两种方法在特定用例上的性能来验证。
          但是,这种技术会带来两个额外的挑战:
        (1)使用不同变量在多个步骤中分割计算会更困难;
        (2)使用条件语句创建适当的过滤器可能更复杂。

          展示这种优化的好处的一个常见例子是:显示基于切片器选择的时间智能度量的计算:比如定义一个元度量[Sales Amount],以及基于该度量添加一个或多个步骤、条件之后的新度量[Smart Sales]。

          原始[Sales Amount]度量和智能[Smart Sales]度量分别定义如下:

          Sales Amount :=
         
    SUMX ( Sales, Sales[Quantity] * Sales[Net Price] )
          Smart Sales := IF ( HASONEVALUE ( Period[Period] ),
          SWITCH ( VALUES ( Period[Period] ),
          "Last week",
          CALCULATE ([Sales Amount], 
          DATESINPERIOD ( 'Date'[Date], MAX ( 'Date'[Date] ),
          VALUES ( Period[Offset] ),DAY )  ),
          "Last 4 weeks",
          CALCULATE ( [Sales Amount],
            DATESINPERIOD (  'Date'[Date],MAX ( 'Date'[Date] ),
            VALUES ( Period[Offset] ),  DAY )  ),
          "Last quarter",
          CALCULATE ( [Sales Amount],
          DATESINPERIOD ( 'Date'[Date],MAX ( 'Date'[Date] ),
          VALUES ( Period[Offset] ),DAY )),
          "MTD", CALCULATE ( [Sales Amount], DATESMTD ( 'Date'[Date] ) ),
          "QTD",  CALCULATE ( [Sales Amount], DATESQTD ( 'Date'[Date] ) ),
          "YTD",  CALCULATE ( [Sales Amount], DATESYTD ( 'Date'[Date] ) ), BLANK()  ))

            该公式中 Swith的多个结果引用的是同一CaⅠculate条件。 Period--周期表包含每个时间段的period列的period  type—周期类型的定义。 在这一列中,“D”表示从所选时间段的最后一天开始的日期范围,“I”表示必须根据时间段名称(MTD, QTD,YTD)在特定时间智能函数中转换的时间段。这里唯一可见的列是Period(其他参数列为隐式),它是上图切片器中使用的列:

            通过定义变量作为Date表的筛选器,你可以只使用单个CALCULATE来重写[Smart Sales]--智能销售度量。 试想,倘若能够使用SWITCH函数来创建该筛器表达式,这当然不失为一个好办法,但遗憾的是:IF和SWITCH都返回标量值而不是表格。 因此不可能编写下面的语法:

    VAR FilterDates = (前面[Smart Sales]度量公式中,从SWITCH开始的部分)

            由于IF与SWITCH无法返回表,因此,可以使用它们定义计算所需的日期范围,并将该时期范围筛选传递给单个DATESBETWEEN函数。 一种可能的实现方式是以下度量:

          简体注:该公式是使用变量来定义筛选器书写DAX步骤的又一个案例。其中变量FirstDaySelected需要具备一定的DAX内部引擎知识。

            [Smart Sales New]度量可能有更好的性能。当然,构建DAX筛选器需要额外的成本,但这可能比定义不同的CALCULATE语句更有效。在本文所示的包含不同[Smart Sales]度量的小样本数据文件中,这种差异并不明显。然而,这种技术在更大的数据库中会产生较大的影响,因为这种类型的数据库不容易复制和下载。
          像往常一样,了解DAX中解决问题的不同方法总是一个好习惯。实际上,性能可能会因需求的具体细节和数据分发的不同而有所不同。
            当出现性能问题时,在没有可用的特殊方式(如考虑索引或聚合优化)来解决问题时。 有必要通过更改DAX代码以获得更好的执行计划。

    相关文章

      网友评论

          本文标题:DAX连接表系列(四) ⅤAR変量(7)

          本文链接:https://www.haomeiwen.com/subject/oftcyftx.html