代码操作 DI005 (改进) 将表筛选器改写为标量谓词
描述
在可能的情况下,将 CALCULATE 的筛选参数改写为标量谓词,而不是使用 FILTER 函数。
示例 1
更改前:
CALCULATE([Total Sales], FILTER(Products, Products[Color] = "Red"))
更改为:
CALCULATE([Total Sales], KEEPFILTERS(Products[Color] = "Red"))
示例 2
更改前:
CALCULATE([Total Sales], FILTER(ALL(Products), Products[Color] = "Red"))
更改为:
CALCULATE([Total Sales], ALL(Products), Products[Color] = "Red")
示例 3
更改前:
CALCULATE(
[Total Sales],
FILTER(
ALL(Products),
Products[Color] = "Red"
&& Products[Class] = "High-end"
)
)
更改为:
CALCULATE(
[Total Sales],
ALL(Products),
Products[Color] = "Red",
Products[Class] = "High-end"
)
Tabular Editor 为什么会提出这种建议?
在 CALCULATE 的筛选参数中使用 FILTER 对表进行筛选,效率不如直接对该表的一列或多列进行筛选。 将筛选器重写为标量谓词后,你的代码会更高效,占用更少的内存和 CPU 资源。
例如,像 FILTER(Sales, < condition >) 这样的表达式会遍历 Sales 表中的所有行,并对每一行计算该条件。 相比之下,像 Sales[Quantity] > 0 这样的表达式只会遍历 Quantity 列,效率高得多,也不会把 Sales 表的所有列都添加到筛选语境中。
使用标量谓词还能让代码更简洁、更易读。
在底层实现中,标量谓词只是语法糖,本质上等价于同样使用 FILTER 函数的表表达式。 不过,FILTER 函数只会应用于单列,因此比筛选整张表更高效。
何时不会显示此建议
从 Tabular Editor 3.25.0 起,当 FILTER 表达式中发生表扩展时,不再建议执行此代码操作。 这是因为在这种情况下,将表筛选重写为标量谓词可能会改变筛选的语义,从而产生不同的结果。
表扩展场景
当 DAX 自动包含关系中“一”端的相关表时,就会发生表扩展。 例如,如果你筛选 Sales 表,DAX 会自动扩展该筛选,使其包含相关的维度表,如 Product、Customer 等。
当你这样写:
CALCULATE(
[Total Sales],
FILTER(Sales, Sales[Quantity] > 10)
)
该筛选会作用于扩展后的 Sales 表,其中包含所有相关的维度表。 这意味着筛选语境不仅包含 Sales 表,还包含与 Sales 存在关系且位于关系“一”端的所有表。
为什么重写会改变结果
将表筛选转换为标量谓词,会改变受影响的表:
原始写法(有表扩展):
CALCULATE([Total Sales], FILTER(Sales, Sales[Quantity] > 10))
这会筛选_扩展后的_ Sales 表,从而影响 Sales 以及所有相关的维度表。
重写后(标量谓词):
CALCULATE([Total Sales], Sales[Quantity] > 10)
这只会筛选 Sales[Quantity] 列,因此不会触发对相关维度表的表扩展。
在大多数情况下,这种差异无关紧要,因为相关的维度表不会影响计算。 不过,在某些情况下,尤其是涉及关系或计算表格时,这两个表达式可能会得到不同的结果。 为确保结果正确,当检测到表扩展时,Tabular Editor 会避免建议进行这种改写。
延伸阅读
- SQLBI: DAX 中的扩展表 —— 全面讲解表扩展的工作原理及其对筛选语境的影响。