前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【性能优化】面向存储引擎,优化基础度量值得到海量性能提升

【性能优化】面向存储引擎,优化基础度量值得到海量性能提升

作者头像
BI佐罗
发布2020-06-19 14:56:20
6100
发布2020-06-19 14:56:20
举报
文章被收录于专栏:PowerBI战友联盟

性能优化,在 DAX 中是很重要的问题,对 DAX 的性能优化大致可以归结为针对 SE(存储引擎) 或 FE(公式引擎) 的性能优化。

如果可以确保 SE 和 FE 都在最好的状态下工作,那么 DAX 将得到充分的发挥。而往往分析师会更加关注业务逻辑的表达,但我们开始研究写出更快的 DAX 时,我们将成为会修车的分析师了。我们会通过一系列文章来帮助大家在各个角度来体会 DAX 的性能优化技术。

今天我们来看一个案例。

看一个案例,我们想知道大订单的个数,如下:

代码语言:javascript
复制
OrderPurchaseNumber =
CALCULATE(
        DISTINCTCOUNT( 'Order'[OrderID] ) ,

        FILTER(
            'Order' ,
            'Order'[LinePrice] > 1000 && 'Order'[LineProfit] > 0
        )
)

大订单的定义为包含单价大于1000且利润大于0的订单。

这个定义没有问题,放在 PowerBI 中的计算也是正确的,但不久就会发现它的性能问题,于是,通过 DAX Studio 来检查可以看到:

我晕,居然惊现了 779 个查询。

该查询的意义是计算每天的大订单个数。但这种方法显然是不行的。虽然在度量值的定义上非常自然。

我们再来看看从 PowerBI 中拖拽的情况,如下:

如果研究该图表背后的 DAX 查询,其结果和上述内容是一致的。

那么问题来了,我们建立了一个基础度量值叫:OrderPurchaseNumber,其逻辑也很清楚,但却有如此之差的性能,怎么办呢?

原因分析

这里的问题在于发起了对 SE 的多次查询,不难察觉:

代码语言:javascript
复制
        FILTER(
            'Order' ,
            'Order'[LinePrice] > 1000 && 'Order'[LineProfit] > 0
        )

这里使用了 Order 表作为 FILTER 的参数,而且位于基础度量值的位置,导致在迭代日期时,每次都会做单独计算,导致对 SE 的过度重复访问。

改进措施

有一种做法是,可以将度量值改为:

代码语言:javascript
复制
OrderPurchaseNumber =
CALCULATE(
        DISTINCTCOUNT( 'Order'[OrderID] ) ,

        FILTER(
            ALL( 'Order' ) ,
            'Order'[LinePrice] > 1000 && 'Order'[LineProfit] > 0
        )
)

注意,这里用了 ALL( ‘Order’ ) 而非 ‘Order’ ,这显然是不对的,因为它改变了语义。

那么进而想到另一种方式为:

代码语言:javascript
复制
OrderPurchaseNumber =
CALCULATE(
        DISTINCTCOUNT( 'Order'[OrderID] ) ,

        FILTER(
            ALL( 'Order'[LinePrice] , 'Order'[LineProfit] ) ,
            'Order'[LinePrice] > 1000 && 'Order'[LineProfit] > 0
        )
)

这样的方式仅仅使用需要用到的两列,而非整个表,来看下效果:

性能得到了非常恐怖的提升。

但细心的伙伴会发现,这种写法的努力方向是对的,但这种写法还是错误的,因为:

代码语言:javascript
复制
        FILTER(
            ALL( 'Order'[LinePrice] , 'Order'[LineProfit] ) ,
            'Order'[LinePrice] > 1000 && 'Order'[LineProfit] > 0
        )

作为筛选器参数,会覆盖外部的筛选,这也是不正确的逻辑,所以,需要进一步优化为:

代码语言:javascript
复制
OrderPurchaseNumber =
CALCULATE( DISTINCTCOUNT( 'Order'[OrderID] ) ,
    KEEPFILTERS(
        FILTER(
            ALL( 'Order'[linePrice] , 'Order'[LineProfit] ) ,
            'Order'[LinePrice] > 1000 && 'Order'[LineProfit] > 0
        )
    )
)

性能结果为:

完美。

总结

当需要在基础度量值中使用筛选条件时,必须注意:

  • 仅仅使用所必须的列,提升性能
  • 使用 KEEPFILTERS 包裹,确保逻辑正确

这样,基础度量值就可以携带复杂的筛选器参数而不影响性能了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PowerBI战友联盟 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原因分析
  • 改进措施
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档