Table of Contents

实现用户自定义聚合

完全导入的事实表会将每一行都缓存在内存中——包括单个订单行、交易 ID 以及行级属性等高基数列,而大多数 Report 使用者其实并不需要这些内容。用户自定义聚合通过将事实表拆分为两部分来解决这一问题:一个小型的预聚合 Import 表,可从内存缓存中处理绝大多数 Report 查询;以及一个 DirectQuery 明细表,用于保存所有行级数据且不占用内存。 Power BI 和 Analysis Services 会自动将每个查询发送到能够响应它的那张表。

迁移到 DirectQuery 的高基数列会带来性能取舍——使用这些列的查询会直接发送到源数据库,而不是由内存引擎提供。将这些列从默认字段列表中隐藏,可确保 Report 使用者默认走快速聚合路径;而需要构建包含行级明细的 Report 的高级用户,也会清楚自己正在使用 DirectQuery 列。

在本教程中,你将为 SpaceParts 模型中的 Orders 事实表配置一个用户定义的聚合。你需要先创建一个以 DirectQuery 模式保存完整行级数据的明细表,然后将现有的 Orders 表配置为聚合表,并设置适当的列映射。

Note

本教程中的步骤同时适用于 Tabular Editor 2 和 Tabular Editor 3。截图使用的是 Tabular Editor 3。

先决条件

开始之前,你需要具备:

  • Tabular Editor 2 或 Tabular Editor 3
  • 一个 Power BI 或 Analysis Services 语义模型,且至少包含一张 Import 事实表
  • 对存储模式(Import、DirectQuery、Dual)有基本了解

聚合的工作原理

聚合模式使用同一张事实表的两个版本:

表 存储模式 用途
聚合表(Orders) 导入 预先聚合并缓存在内存中的数据。用于回答汇总查询。
明细表(Order details) DirectQuery 在数据源端查询完整的行级数据。当聚合无法回答该查询时使用。

维度表设置为 Dual 存储模式,以便同时参与 Import 和 DirectQuery 两种查询路径。

只把表设置为 Dual 或 DirectQuery 存储模式并不会启用聚合路由——它只会创建一个复合模型,查询会根据存储模式被路由。启用用户自定义聚合的关键是 Alternate Of 属性:它会创建显式的列级映射,告诉引擎“当查询从明细表请求这一列时,可以改用这个预聚合列。”如果没有 Alternate Of,引擎就没有进行替换的依据,也不会将查询路由到聚合表。引擎会根据这些映射评估每个传入的查询,以确定聚合表是否能够回答该查询;只有在不能回答时,才会回退到 DirectQuery。

Important

DirectQuery 存在一些已知限制,会影响模型设计和 Report 功能。与此模式最相关的包括:针对 DirectQuery 列的查询依赖数据源响应时间;云数据源每个查询最多返回一百万行;DirectQuery 表无法使用自动日期/时间层次结构;并且部分 DAX 函数在 DirectQuery 模式下不受支持。在继续之前,请先查看完整列表:在 Power BI Desktop 中使用 DirectQuery。

步骤 1:将维度表设置为 Dual 存储模式

与事实表相关的每个维度表都必须设置为 Dual 存储模式。这使引擎能够在 Import 和 DirectQuery 两种查询路径中使用维度属性。

对每个维度表(Customers、Products):

  1. 在 TOM Explorer 中展开该表,然后展开 Partitions。
  2. 选择该分区。
  3. 在 Properties 面板中,找到 Options 下的 Mode 字段,并将其设置为 Dual。

在 TOM Explorer 中选中 Customers 分区,并在 Properties 面板中将 Mode 设为 Dual

对每个与事实表存在关系的维度表重复上述操作。

步骤 2:创建明细表

明细表是原始事实表的副本,配置为在 DirectQuery 模式下直接向数据源发起查询。它会对 Report 使用者隐藏——其唯一用途是处理聚合表无法回答的明细粒度查询。

复制事实表

创建 Orders 表的副本,并将其命名为 Order details。在 Tabular Editor 中,你可以选中 Orders 表,然后在右键菜单中选择 Duplicate 1 table 来完成此操作。

将分区设置为 DirectQuery

  1. 在 TOM Explorer 中,展开 Order details,然后展开 分区。
  2. 选择该分区。
  3. 在 Properties 面板中,将 Mode 设置为 DirectQuery。

在 TOM Explorer 中选择 Order details 分区,并在 Properties 面板中将 Mode 设置为 DirectQuery

删除度量值

从 Orders 复制过来的任何 DAX 度量值——比如 Quantity 和 Value——都应该从 Order details 里删掉。度量值应放在聚合表中,而不是明细表中。

隐藏所有列和该表

选中 Order details 中的所有列,并在 Properties 面板中将 Hidden 设置为 True。然后选择 Order details 表本身,并将 Hidden 也设置为 True。

Note

隐藏明细表及其所有列,可确保 Report 使用者始终只与聚合表交互。明细表是聚合架构中的实现细节。

步骤 3:创建关系并设置“Rely On Referential Integrity”

明细表需要与聚合表相同的维度表关系,这样引擎才能正确路由 DirectQuery 查询。

在 Order details 表中创建以下关系:

  • Order details[Customer Key] → Customers[Customer Key]
  • Order details[Product Key] → Products[Product Key]

对于上述每条新建关系,请在“属性”窗格中将 Rely On Referential Integrity 设置为 True。

在 TOM Explorer 中选中从 Order details 到 Products 的关系,并在“属性”窗格中将 Rely On Referential Integrity 设置为 True

Note

Rely On Referential Integrity 用于指示引擎在生成 DirectQuery SQL 时使用 INNER JOIN,而非 OUTER JOIN。这可以提升查询性能,并且在明细表中的每个外键值都能在维度表中找到匹配行时,可以安全启用。

步骤 4:精简聚合表

聚合表(Orders)应只包含引擎进行聚合路由所需的内容:

  • 关系键列:Customer Key、Product Key — 用于匹配维度筛选条件
  • 基础数值列:Net Order Quantity、Net Order Value — 下一步将映射到明细表中的列
  • DAX 度量值:Quantity、Value

删除 Orders 中所有其他列——日期、单据号、状态字段,以及任何其他属性列。这些仅存在于 Order details 中。

Note

要让聚合路由正常工作,任何聚合表中不存在的属性列,都必须存在于明细表中。当查询引用了聚合表中不存在的列时,引擎会回退到 DirectQuery,因此明细表必须完整保留一份事实数据的副本。

这种模式最适用于在 Report 中很少使用的高基数列——例如单笔交易 ID、单据编号、行级状态字段以及类似属性。如果事实表里还有在 Report 中经常出现的低基数列(例如区域代码或产品类别标记),可以考虑把这些列移到 Dual 模式的维度表中,这样这些列将由内存缓存提供,而不是通过 DirectQuery 获取。

Tip

另外,还可以将 Orders 表的 Hidden 属性设置为 True,以隐藏 Orders 表本身。与明细表一样,聚合表也是实现细节,不应出现在 Report 字段列表中。

步骤 5:更新度量值,使其引用明细表

聚合表上的度量值必须引用明细表,而不是聚合表本身。这正是引擎能够正确回退到 DirectQuery 的原因:当查询无法从内存缓存中得到结果时,引擎会根据度量值的引用转到 Order details 并查询数据源。

将 Orders 上的每个度量值更新为引用 Order details 中对应的列:

// Quantity
SUM( 'Order details'[Net Order Quantity] )
// Value
SUM( 'Order details'[Net Order Value] )
Note

度量值不一定要放在聚合表上。它们可以定义在 Order details 上,也可以定义在模型中的任何其他表上——例如一个专用的空度量值表。为简化说明,本教程中将它们保留在 Orders 上。

步骤 6:配置 Alternate Of 属性

对于聚合表中的每个数值型基础列,配置 Alternate Of 属性,以告诉引擎它对应明细表中的哪一列。

  1. 在 TOM Explorer 中,展开 Orders 表并选择一个基础列——例如 Net Order Quantity。
  2. 在 属性 面板中,展开 Alternate Of 分组。
  3. 将 Base Column 设置为明细表中对应的列:Order details[Net Order Quantity]。
  4. 确认 Summarization 设置为 Sum。

在 Orders 表中选中 Net Order Quantity 列,将 Alternate Of Base Column 设置为 Order details[Net Order Quantity],并将 Summarization 设置为 Sum

对 Net Order Value 重复上述操作,将其映射到 Order details[Net Order Value],并设置 Summarization: Sum。

验证结果

Tabular Editor 中的图表视图显示已完成的聚合架构。 Orders 和 Order details 都通过两组并行关系连接到相同的维度表。

Tabular Editor 图表视图,显示 Orders 聚合表和 Order details 明细表,两者均通过关系连接到 Customers 和 Products

在 Power BI Desktop 中,模型视图会以存储模式图标和颜色编码显示相同的结构:维度表显示 Dual 存储模式指示器,Order details 显示为 DirectQuery 且已隐藏,Orders 显示为 Import 且已隐藏。

Power BI Desktop 模型视图,显示已完成的聚合设置:Dual 模式的维度表、隐藏的 Import 聚合表,以及隐藏的 DirectQuery 明细表

延伸阅读