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

        变量(4)

    使用变量优化重复的DAX表达式

        通过前面关于变量的介绍,知道了它的几个特点:
      1、变量实际是一个由存储引擎加载在内存里的存储数据。在这点上,其实际与Powerqurey里的Buffer函数相似。
      比如我们在Powerqurey里求累计占比时,事先使用List.Buffer函数将计算列缓存起来,以便用于该列的累计计算时的分子、分母。

      然后根据该缓存的列,定义每行的值与该列的总值(绝对值)的计算(作为累计聚合计算时的分子、分母值)

        2、由于变量实际上更像一个“常量”,这与DAX的值列表类似,因而常用于构建DAX的逻辑条件(替代难于理解的“当前行”,充当行筛选等);还因为变量在存储引擎里作为“固定的存储数据(更像“常量”)”被公式引擎引用,而且是一次性计算,从而使公式不必直接从数据模型请求引用数据的迭代。

        3、正确使用变量也有助于提高查询性能。这是本节需要讨论的问题。
        (以下内容有参考官方的简体笔记部分)
        本节内容介绍如何使用变量来优化包含同一度量或同一子表达式的多个引用实例的DAX表达式的性能。通过前面的介绍,我们已经知道:在 DAX 中, 应该考虑使用度量作为提高表达式可读性的一种方法。但是, 正确使用变量也有助于提高查询性能。
      实际上, 这意味着更好的执行计划:因为这样可以避免同一变量或子表达式在同一筛选器中的多次引用。例如, 在Power BI 数据模型中考虑此简单动态分割模式的实现。


        Segments表定义了三个细分市场的划分范围,这些将用于根据客户的支出情况对其细分市场进行聚类(群组)。

        在使用变量之前,我们先编写原始的动态分割模式。因此, 第一次实施分段的Customer Sales-- Customer Sales度量如下:

        Sales[Customers Sales] :=
        IF ( ISCROSSFILTERED ( Segments ),
        SUMX (  Segments,
        SUMX ( Customer,
        IF ( [Sales Amount] >= Segments[MinValue]  //上边界
        && [Sales Amount] < Segments[MaxValue],//下边界
        [Sales Amount]))),  [Sales Amount])

        使用Customer Sales表获得的报告显示了相应的结果。

      但是, 在Customer--客户表的 SUMX 迭代中,在相同的列表筛选和行筛选中, Sales Amount度量值有三次被引用 :

      理想状态下, 查询引擎应该能够识别到这三个引用的结果对于给定的客户定义来说总是相同的。这在现在的最新Powerpivot或Power BI里是可以的, 但2018年1月前的情况并非如此。
      使用 DAX STUDIO, 可以看到以前版本的报告中由 Customer Sales度量生成的存储引擎查询。

      两个突出显示的行显示了由存储引擎查询返回的数据缓存:两者行数相同、大小相同、查询的初始部分看起来也相同。不过,两个存储引擎查询又有所不同。第一个引擎查询如下:

        WITH
      $Expr0 := ( PFCAST ( 'Sales'[Quantity] AS  INT )  * PFCAST ( 'Sales'[Net Price] AS  INT )  )                  SELECT
      'Customer'[CustomerKey], SUM ( @$Expr0 )
      FROM 'Sales'
      LEFT OUTER JOIN 'Customer' ON
      'Sales'[CustomerKey]='Customer'[CustomerKey];

      第二个引擎查询提供了附加的过滤条件(在前一个代码的后面加上WHERE过滤条件):
      WHERE  'Customer'[CustomerKey] IN ( 13407, 9266, 17548, 7787, 3646, 17055,                    12914, 18041, 7294,3153… [18869 total values, not all displayed]  ) ;

        请记住,存储引擎查询显示了每个数据缓存的行的估计大小值。实际数值在物理查询计划的Spool _ Iterator事件中可用,它对应于结果为18,869,这是实际的客户数,且两个数据缓存的结果相同。
      由于查询优化器假设IF函数的两个参数可能有不同的结果,因而它对存储引擎会提出两个相同结果的数据引用请求。如果对查询语义进行更深入的分析,应该允许让查询优化器这样做,这将更好。但我们已说过,这在2018年1月前的引擎版本中还没有该性能优化。
      作为实验,使用变量,可以参考IF函数在不同参数中的变量值,针对每个客户只评估一次Sales Amount---销售额度量。

        以下是 Customer Sales度量的优化版本:
        Sales[Customers Sales Optimized] :=
        IF ( ISCROSSFILTERED ( Segments ),
        SUMX ( Segments,
        SUMX ( Customer,
        VAR SalesAmount = [Sales Amount]
        RETURN
       
IF ( SalesAmount >= Segments[MinValue]
        && SalesAmount < Segments[MaxValue],
              SalesAmount))),[Sales Amount])

        使用这种方法的度量,物理查询计划更短,这时候,每个客户的销售金额结果都将分别对应一个数据缓存(加粗的三个位置已被同一变量替代):
        上述公式里,最后一个[Sales Amount] 为什么不能使用由该度量定义的变量,前一篇文里已讲过。这里从略。


        加粗显示的行是用于计算所有客户的销售金额的单个 datacache--数据缓存, 它不包含任何筛选条件(更像一个“常量”)。

        WITH $Expr0 := ( PFCAST ( 'Sales'[Quantity] AS  INT )
        * PFCAST ( 'Sales'[Net Price] AS  INT )  )
        SELECT  'Customer'[CustomerKey],
        SUM ( @ $Expr0 )FROM 'Sales'
        LEFT OUTER JOIN 'Customer' ON
        'Sales'[CustomerKey]='Customer'[CustomerKey];

      如果物化越小,则查询性能越好。但这在小数据模型中几乎无法测量,只有在拥有大量客户的数据模型中,才会很容易看到这种差异。
      当相同的子表达式在相同的计算筛选条件下多次被引用时, 也可以进行类似的性能优化。
      例如,不包含度量值引用的 Customer Sales版本, 它重复相同的计算次数。 优化的版本则提供了以前显示的相同方法。有一个CALCULATE语句的单一评估, 其结果将多次引用 SalesAmount 变量。
      在 DAX 中, 变量提供了更好的代码可读性, 并通过减少同一子表达式多次出现的计算几率, 以促进更优化的查询计划的生成。

      未完待续

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容