设计可扩展的计算
模型是结构化的。 现在,设计计算方法,以便在数据和团队增长的过程中保持高性能和可维护性。 在小规模,具有重复度量值和不一致的命名的模型仍然有效,即使它不理想。 在大规模情况下,它会崩溃。 具有数百个度量值的模型需要结构设计决策,防止重复逻辑,减少大型数据集的查询时间,并使新团队成员能够理解和扩展模型,而无需引入错误。
本单元涵盖三种模式:用于减少度量值扩散的计算组、团队可维护性的 DAX 可读性规则,以及针对大型事实数据表查询性能的聚合。
计算组
计算组是跨多个度量值应用相同计算模式的模型对象。 无需为每个变体创建单独的度量值,而是定义一次模式并动态应用该模式。
计算组所解决的问题
考虑具有 50 个基本度量值(如总销售额、总成本、利润和销售单位)的组织。 每个度量值都需要“年初至今”、“本季度至今”和“本月至今”的计算。 如果没有计算组,则为 50 × 3 = 150 个额外度量值。 加入对上一年的比较,这意味着您需要查看250多个需要维护的指标。
使用计算组,可以为每个时间智能模式创建一个包含计算项的组。 这些项自动应用于模型中的任何度量值。
计算组的工作原理
计算组中包含计算项,每个计算项定义一个 DAX 表达式,该表达式使用 SELECTEDMEASURE() 修改当前度量值。 下面是时间智能计算组:
// Year-to-Date
CALCULATE(
SELECTEDMEASURE(),
DATESYTD('Date'[Date])
)
// Quarter-to-Date
CALCULATE(
SELECTEDMEASURE(),
DATESQTD('Date'[Date])
)
// Month-to-Date
CALCULATE(
SELECTEDMEASURE(),
DATESMTD('Date'[Date])
)
当用户将计算组添加到某个视觉对象后,他们便能够对任意度量值(例如总销售额、利润或销售数量)在 YTD、QTD 和 MTD 之间进行切换,而无需为每一种可能的组合都单独创建一个度量值。
动态格式字符串
动态格式字符串根据计算项上下文更改显示格式。 例如,百分比计算应显示为百分比,而货币计算应显示为货币,即使应用于相同的基准度量值也是如此。
// In the format string expression for a YoY % calculation item:
"0.0%"
动态格式字符串减少了对单独的格式化度量值的需求,并使格式在整个模型中保持一致。
小窍门
详细了解如何在 Power BI 中创建计算组
何时使用计算组
当您有三个或多个度量需要应用相同的计算模式时,请使用计算组。 常见用例包括时间智能(YTD、QTD、MTD)、货币换算和方差计算(实际与预算)。
DAX 可读性准则
当规模扩大至由团队维护 200 多个度量值时,可读性就成为一种设计决策,而不再仅是个人的偏好问题。 一致且可读的 DAX 可减少维护错误,并使新团队成员更容易理解模型。
变量
变量存储中间结果,提高可读性,并防止引擎多次计算相同的表达式:
Profit Margin =
VAR TotalRevenue = SUM(Sales[Revenue])
VAR TotalCost = SUM(Sales[Cost])
VAR ProfitAmount = TotalRevenue - TotalCost
RETURN
DIVIDE(ProfitAmount, TotalRevenue)
如果没有变量,同 SUM(Sales[Revenue]) 一表达式可能会在复杂度量值中出现三次。 变量计算表达式一次并重复使用结果。
小窍门
详细了解 如何使用变量改进 DAX 公式。
命名约定
当模型具有由多人维护的数百个度量值时,一致的命名至关重要。 建立规范:
- 度量值名称:使用清晰的描述性名称,如“总销售额”或“YoY 收入增长”。避免仅原始作者理解的缩写。
-
变量名称:使用描述性名称来解释中间值(如
TotalRevenue而不是x或temp)。 - 计算组中的项:应根据这些项的功能来命名,而不是依据它们的实现方式(例如,应命名为“年初至今”,而不是“DATESYTD 包装器”)。
描述性命名对于 AI 使用也很重要。 当 Copilot 或数据智能体查询模型时,它会依据度量值的名称和描述来判断应该将哪些计算结果包含进来。 名为“YoY 收入增长”的度量值比“Calc7_v2”产生更好的 AI 结果。
小窍门
Power BI中的Copilot可以帮助编写和解释 DAX 公式。 在处理复杂度量值时,请使用Copilot来建议改进或解释现有逻辑。
迭代器与聚合函数
迭代器函数 (SUMX, , AVERAGEXMAXX) 对表的逐行表达式求值。 聚合函数 (SUM, , AVERAGEMAX) 对单个列进行操作。 在大量数据中,选择很重要:
- 在汇总单个列时使用聚合函数。 它们速度更快,因为引擎可以使用预生成的数据结构。
- 当计算需要行级表达式(如
Quantity × UnitPrice每行)时使用迭代器。
注释
迭代器处理每一行,这可能会影响大型事实数据表的性能。
防御模式的信息函数
信息函数(例如 ISBLANK、HASONEVALUE 和 ISINSCOPE)为具有不同筛选器上下文的多个报表中使用的度量值创建了防御模式。
Sales per Customer =
IF(
HASONEVALUE(Customer[CustomerID]),
DIVIDE(SUM(Sales[Amount]), 1),
DIVIDE(SUM(Sales[Amount]), DISTINCTCOUNT(Sales[CustomerID]))
)
当原始作者未预料到的上下文中使用度量值时,这些模式可防止意外结果。
Aggregations
聚合表是一种摘要表,它以比明细数据更粗的粒度来存储预先计算好的总计数值。 查询优先处理这些表,从而提高大型事实表的性能。 当查询与聚合匹配时,引擎会从较小的摘要表返回结果,而不是扫描数百万个详细信息行。
聚合作为设计决策
确定何时添加聚合以及具体粒度是设计决策。 性能监视和优化是单独的操作问题,但在模型设计过程中会做出结构选择。
在以下情况下考虑聚合:
- 事实数据表超过数百万行,常用查询以更高的粒度汇总数据(例如按区域每月汇总)。
- 用户在摘要级视觉对象上遇到查询响应时间缓慢的问题。
- 大多数报表交互不需要行级详细信息。
聚合行为与存储模式有何不同
在导入模式下,聚合存储为单独的隐藏表。 引擎会自动将匹配的查询路由到聚合表。
在 Direct Lake 模式下,Delta 表本身可以充当聚合源。 由于 Direct Lake 读取列式 Parquet 文件,因此引擎可以在很多情况下处理较大的数据量,而无需聚合。 仅当查询模式确认需要时才添加聚合。
小窍门
详细了解 Power BI 中用户定义的聚合。