Power BI Desktop 中的模型关系
- 版本 :2023.1(当前版本)
Power BI Desktop 中的模型关系
本文主要面向使用 Power BI Desktop 的 Import 数据建模者。 这是重要的模型设计主题,对于提供直观、准确的最佳模型至关重要。
若要更深入地探讨包括表角色和关系在内的最佳模型设计,请参阅了解星型架构及其对 Power BI 的重要性。
关系用途
模型关系会将应用于模型表列的筛选器传播到其他模型表。 只要有关系路径可循,筛选器就会进行传播,这可能涉及传播到多个表。
关系路径是确定性的,这意味着筛选器始终以相同的方式传播,而不会随机变化。 但是,可以禁用关系,或通过使用特定 DAX 函数的模型计算来修改筛选器上下文。 有关详细信息,请参阅本文稍后介绍的相关 DAX 函数主题。
重要
模型关系不强制实施数据完整性。 有关详细信息,请参阅本文稍后介绍的关系计算主题,此主题介绍了当数据存在数据完整性问题时模型关系的行为。
下面通过一个动画示例演示了关系如何传播筛选器。
在此示例中,模型由四个表组成:Category、Product、Year 和 Sales。 Category 表关联到 Product 表,而 Product 表关联到 Sales 表。 Year 表也关联到 Sales 表。 所有关系均为一对多(本文后面将对此进行详细介绍)。
查询可能是由 Power BI 卡视觉对象生成,请求获取单个类别 Cat-A 和单个年份 CY2018 的销售订单的总销售量。 正因为此,可以看到 Category 和 Year 表上应用的筛选器。 Category 表上的筛选器传播到 Product 表,分离出分配给类别 Cat-A 的两个产品。 然后,Product 表筛选器传播到 Sales 表,针对这些产品分离出两个销售行。 这两个销售行表示分配给类别 Cat-A 的产品的销量。 其总量为 14 个单位。 与此同时,传播 Year 表筛选器以进一步筛选 Sales 表,最终得到一个销售行,该行对应于分配给类别 Cat-A 并于 CY2018 年订购的产品。 该查询返回的数量值为 11 个单位。 请注意,向某个表应用多个筛选器时(例如本示例中的 Sales 表),始终进行 AND 运算,即,要求所有条件都必须成立。
应用星型架构设计原则
建议应用星型架构设计原则来生成包含维度表和事实数据表的模型。 设置 Power BI 来强制实施筛选维度表的规则,使模型关系能够有效地将这些筛选器传播到事实表,这是很常见的做法。
下图是 Adventure Works 销售分析数据模型的模型图。 它显示了一个星型架构设计,其中包含一个名为“Sales”事实表。 其他四个表是支持按日期、状态、区域和产品分析销售度量值的维度表。 请注意连接所有表的模型关系。 这些关系将筛选器(直接或间接)传播到“Sales”表。
断开连接的表
一个模型表与另一个模型表不关联的情况不太常见。 有效模型设计中的此类表称为断开连接的表。 断开连接的表不用于将筛选器传播到其他模型表, 它接受“用户输入”(可能包含切片器视觉对象),从而使模型计算能够以有意义的方式使用输入值。 例如,假设有一个断开连接的表,表中加载了一系列货币汇率值。 只要应用筛选器以按单个费率值进行筛选,度量值表达式就可以使用此值来转换销售值。
Power BI Desktop what-if 参数是一个用于创建断开连接的表的功能。 有关详细信息,请参阅在 Power BI Desktop 中创建并使用 What if 参数来可视化变量。
关系属性
模型关系可将一个表中的一列关联到另一个表中的一列。 (在一种特殊情况下,此要求不成立,它只适用于 DirectQuery 模型中的多列关系。有关详细信息,请参阅 COMBINEVALUES DAX 函数文章。)
备注
无法将同一表中的一列关联到另一列。 此概念有时会与能够定义表自引用的关系数据库外键约束相混淆。 你可以使用此关系数据库概念存储父子关系(例如,每条员工记录均关联到一个“汇报对象”员工)。 但是,不能使用模型关系生成基于此类关系的模型层次结构。 若要创建父子层次结构,请参阅父函数和子函数。
基数
每个模型关系都由基数类型定义。 一共有四个基数类型选项,表示“从”和“到”相关列的数据特征。 “一”侧表示该列包含唯一值;“多”侧表示该列可以包含重复值。
备注
如果数据刷新操作尝试将重复值加载到“一”侧列中,则整个数据刷新将失败。
以下项目符号列表描述了这四个选项及其速记符号:
一对多 (1:*)
多对一 (*:1)
一对一 (1:1)
多对多 (*:*)
当你在 Power BI Desktop 中创建关系时,设计器会自动检测并设置基数类型。 Power BI Desktop 会查询模型,以了解哪些列包含唯一值。 对于 Import 模型,它使用内部存储统计信息;对于 DirectQuery 模型,它向数据源发送分析查询。 但是,Power BI Desktop 有时可能会出错。 如果表中尚未加载数据,或你希望包含重复值的列当前包含唯一值,它可能会出错。 不论是哪种原因,只要任何“一”端列包含唯一值(或表中尚未加载数据行),你都可以更新基数类型。
一对多(和多对一)基数
“一对多”和“多对一”基数选项基本相同,并且它们也是最常见的基数类型。
配置一对多或多对一关系时,将选择与列关联顺序匹配的关系。 设想一下,如何使用每个表中的 ProductID 列来配置从 Product 表到 Sales 表的关系。 基数类型将为一对多,因为 Product 表中的 ProductID 列包含唯一值。 如果将表反向关联,即 Sales 到 Product,则基数为多对一。
一对一基数
一对一关系意味着两个列都包含唯一值。 这种基数类型并不常见,并且由于冗余数据的存储,它可能代表了不太理想的模型设计。
若要详细了解如何使用此基数类型,请参阅一对一关系指南。
多对多基数
多对多关系意味着两个列都可以包含重复值。 这种基数类型很少使用。 在设计复杂的模型需求时,它通常很有用。 可以使用它来关联多对多事实或关联更高粒度的事实。 例如,当销售目标事实存储在产品类别级别,并且产品维度表存储在产品级别时。
有关使用此基数类型的指南,请参阅多对多关系指南。
备注
为 Power BI 报表服务器开发的模型目前不支持“多对多”基数类型。
提示
在 Power BI Desktop 模型视图中,可以通过查看关系线两端的指示符(1 或 *)来解释关系的基数类型。 若要确定关联了哪些列,你需要选择关系线或将光标悬停在其上方,以突出显示这些列。
交叉筛选器方向
为每个模型关系定义交叉筛选方向。 你的设置将决定筛选器的传播方向。 可能的交叉筛选选项取决于基数类型。
基数类型 交叉筛选选项
一对多(或多对一) 单向
两者
一对一 两者
多对多 单(Table1 到 Table2)
单(Table2 到 Table1)
两者
单交叉筛选方向表示“单向”,双表示“双向”。 在两个方向进行筛选的关系通常称为双向。
在一对多关系中,交叉筛选方向始终从“一”侧开始,也可以选择从“多”侧开始(双向)。 在一对一关系中,交叉筛选方向始终同时从两个表开始。 最后,在多对多关系中,交叉筛选方向可以从其中一个表开始,也可以同时从两个表开始。 请注意,当基数类型包括“一”侧时,此类筛选器将始终从该侧传播。
当交叉筛选方向设置为“双向”时,其他属性变为可用。 当 Power BI 强制实施行级安全 (RLS) 规则时,它可以应用双向筛选。 若要详细了解 RLS,请参阅结合使用行级别安全性 (RLS) 与 Power BI Desktop。
也可以通过模型计算来修改关系交叉筛选方向(包括禁用筛选器传播)。 这是通过使用 CROSSFILTER DAX 函数来实现的。
请记住,双向关系可能会对性能产生负面影响。 此外,尝试配置双向关系可能会导致筛选器传播路径不明确。 在这种情况下,Power BI Desktop 可能无法提交关系更改,并通过错误消息发出警报。 但是,有时 Power BI Desktop 可能允许你在表之间定义不明确的关系路径。 后文将介绍如何解决关系路径多义性的问题。
建议仅在需要时使用双向筛选。 有关详细信息,请参阅双向关系指南。
提示
在 Power BI Desktop 模型视图中,可以通过观察关系线的箭头来解释关系的交叉筛选方向。 单箭头表示沿箭头方向的单向筛选器;双箭头表示双向关系。
激活此关系
两个模型表之间只能有一条活动的筛选器传播路径。 你可以引入其他关系路径,但必须将这些关系都设置为非活动状态。 只能在模型计算评估期间激活非活动关系。 这可以通过 USERELATIONSHIP DAX 函数来实现。
通常,建议尽可能定义活动关系。 此类关系扩大了报表作者如何使用模型的范围和可能性。 仅使用活动关系意味着应在模型中复制角色扮演维度表。
不过,在特定情况下,可以为角色扮演维度表定义一个或多个非活动关系。 在以下情况下,可以考虑这种设计:
不要求报表视觉对象同时按不同角色进行筛选。
使用 USERELATIONSHIP DAX 函数激活特定关系,以进行相关模型计算。
有关详细信息,请参阅活动与非活动关系指南。
提示
在 Power BI Desktop 模型视图中,可以解释关系的活动状态与非活动状态。 活动关系用实线表示;非活动关系用虚线表示。
假设引用完整性
假设引用完整性属性仅适用于属于同一源组的两个 DirectQuery 存储模式表之间的一对多和一对一关系。 仅当“多”侧列不包含 NULL 时,才能启用此属性。
启用后,发送到数据源的本机查询会使用 INNER JOIN(而不是 OUTER JOIN)来联接两个表。 通常,启用此属性可以提高查询性能,但具体取决于数据源的详细情况。
当两个表之间有数据库外键约束时,始终启用此属性。 即使没有外键约束,但只要确定特定数据完整性存在,就可以考虑启用此属性。
重要
如果数据完整性受到损害,内部联接将消除表之间不匹配的行。 例如,假设有一个模型 Sales 表,其中的 ProductID 列值在关联 Product 表中不存在。 从 Product 表到 Sales 表的筛选器传播将消除未知产品的销售行。 这会导致低估销售结果。
有关详细信息,请参阅 Power BI Desktop 中的假设引用完整性设置。
相关 DAX 函数
有几个与模型关系相关的 DAX 函数。 以下项目符号列表简要介绍了每个函数:
RELATED:从关系的“一”侧检索值。 当涉及在行上下文中评估的不同表的计算时,此函数会很有用。
RELATEDTABLE:从关系的“多”侧检索表行。
USERELATIONSHIP:允许计算使用非活动关系。 (从技术上讲,此函数修改特定非活动模型关系的权重,有助于影响其使用。)当模型包含角色扮演维度表并且你选择从此表创建非活动关系时,此函数会很有用。 你还可以使用此函数来解决筛选器路径多义性的问题。
CROSSFILTER:修改关系交叉筛选方向(单或双),或者禁用筛选器传播(无)。 当你需要在评估特定计算期间更改或忽略模型关系时,此函数会很有用。
COMBINEVALUES:将两个或更多个文本字符串联接成一个文本字符串。 此函数的目的是,在表属于同一源组时支持 DirectQuery 模型中的多列关系。
TREATAS:将表表达式的结果作为筛选器应用于无关表中的列。 当在评估特定计算期间创建虚拟关系时,此函数在高级场景中非常有用。
父函数和子函数:可用来生成计算列以归化父子层次结构的一系列相关函数。 然后你可以使用这些列创建固定级别的层次结构。
关系评估
从评估的角度来看,模型关系可分为“常规”或“有限” 。 此关系属性不可配置。 事实上,它是从两个关联表的基数类型和数据源推断出来的。 了解评估类型非常重要,因为如果数据完整性受到损害,可能会产生一些性能影响或后果。 本主题将介绍这些影响和完整性后果。
首先,需要通过一些建模理论来充分了解关系评估。
Import 或 DirectQuery 模型从 Vertipaq 缓存或源数据库中获取其所有数据。 在这两个实例中,Power BI 都能确定某个关系的“一”侧是否存在。
但是,Composite 模型可能由使用不同存储模式(Import、DirectQuery 或双重)或多个 DirectQuery 源的表组成。 每个源(包括导入数据的 Vertipaq 缓存)都被视为一个源组。 这样,就可以将模型关系分类为源组内或各源组间/跨源组。 源组内关系将源组内的两个表相关联,而源组间/跨源组间关系将两个源组中的表相关联。 请注意,Import 或 DirectQuery 模型中的关系始终是源组内关系。
下面是 Composite 模型的一个示例。
在此示例中,Composite 模型由两个源组组成:Vertipaq 源组和 DirectQuery 源组。 Vertipaq 源组包含三个表,而 DirectQuery 源组包含两个表。 该示例中存在一个跨源组关系,即将 Vertipaq 源组中的表关联到 DirectQuery 源组中的表。
常规关系
当查询引擎可以确定关系的“一”侧时,模型关系为“常规”。 它已确认“一”侧列包含唯一值。 所有一对多的源组内关系都是常规关系。
下面的示例中有两个常规关系,均标记为“R”。关系包括 Vertipaq 源组中包含的一对多关系和 DirectQuery 源中包含的一对多关系。
对于 Import 模型,其所有数据都存储在 Vertipaq 缓存中,Power BI 会在数据刷新时为每个常规关系创建一个数据结构。 数据结构由所有列到列值的索引映射组成,其用途是在查询时加快表的联接速度。
在查询时,常规关系允许进行表扩展。 表扩展会包含基表的本机列,然后扩展到关联表中,从而创建虚拟表。 对于 Import 表,表扩展在查询引擎中完成;对于 DirectQuery 表,表扩展在发送到源数据库的本机查询中完成(前提是未启用“假定引用完整性”属性)。 然后,查询引擎对扩展表进行操作,应用筛选器,并按扩展表列中的值进行分组。
备注
非活动关系也会进行扩展,即使计算操作未使用该关系也是如此。 双向关系对表扩展没有影响。
对于一对多关系,使用 LEFT OUTER JOIN 语义从“多”侧到“一”侧进行表扩展。 当从“多”侧到“一”侧的匹配值不存在时,会向“一”侧表添加一个空白虚拟行。 此行为仅适用于常规关系,不适用于有限关系。
表扩展也适用于一对一的源组内关系,但要使用 FULL OUTER JOIN 语义。 此联接类型可确保必要时在任一侧添加空白虚拟行。
空白虚拟行实际上是未知成员。 未知成员表示引用完整性冲突,其中“多”侧值没有对应的“一”侧值。 理想情况下,不应存在这些空白行。 可以通过清理或修复源数据来消除它们。
下面通过一个动画示例演示了表扩展的工作原理。
在此示例中,模型由三个表组成:Category、Product 和 Sales。 Category 表通过一对多的关系关联到 Product 表,而 Product 表通过一对多的关系关联到 Sales 表。 Category 表包含两行,Product 表包含三行,Sales 表包含五行。 所有关系的两侧都有匹配的值,这意味着不存在引用完整性冲突。 系统会显示一个查询时扩展表。 该表由这三个表中的列组成。 实际上,它是三个表中所含数据的非规范化透视图。 将向 Sales 表添加一个新行,其中包含一个生产标识符值 (9),该值在 Product 表中没有匹配值。 这是一个引用完整性冲突。 在扩展表中,新行针对 Category 和 Product 表列具有 (Blank) 值。
有限关系
当没有确定的“一”侧时,模型关系为“有限”。 关系受限可能出于以下两个原因:
该关系使用多对多基数类型(即使其中一列或两列都包含唯一值)。
该关系跨源组(这种情况仅适用于 Composite 模型)。
下面的示例中有两个有限关系,均标记为“L”。这两个关系包括一对多跨源组关系和 Vertipaq 源组中包含的多对多关系。
对于 Import 模型,永远不会为有限关系创建数据结构。 在这种情况下,Power BI 在查询时解析表联接。
对于有限关系,永远不会发生表扩展。 表联接是使用 INNER JOIN 语义实现的,因此不会添加空白虚拟行来补偿引用完整性冲突。
还有一些与受限关系相关的限制:
无法使用 RELATED DAX 函数来检索“一”侧列值。
强制实施 RLS 时具有拓扑限制。
提示
在 Power BI Desktop 模型视图中,可以将关系解释为受到限制。 有限关系通过基数指示器后面的类似于圆括号的标记 ( ) 表示。
解决关系路径多义性的问题
双向关系可以在模型表之间引入多个(因此不明确)筛选器传播路径。 在评估多义性时,Power BI 根据其优先级和权重选择筛选器传播路径。
优先度
优先级层定义 Power BI 用于解决关系路径多义性问题的一系列规则。 第一个规则匹配决定 Power BI 将遵循的路径。 以下每个规则都描述了筛选器如何从源表流向目标表。
由一对多关系组成的路径。
由一对多或多对多关系组成的路径。
由多对一关系组成的路径。
由从源表到中间表的一对多关系以及从中间表到目标表的多对一关系组成的路径。
由从源表到中间表的一对多或多对多关系以及从中间表到目标表的多对一或多对多关系组成的路径。
任何其他路径。
某一关系包含在所有可用路径中时,应将其从所有路径中删除。
重量
路径中的每个关系都有一个权重。 默认情况下,除非使用 USERELATIONSHIP 函数,否则每个关系权重均相等。 路径权重是路径上所有关系权重中的最大值。 Power BI 使用路径权重来解决同一优先级层中的多个路径之间的多义性问题。 它不会选择优先级较低的路径,而是选择权重较高的路径。 路径中的关系数量不影响权重。
你可以使用 USERELATIONSHIP 函数来影响关系的权重。 权重由对此函数的调用的嵌套级别决定,其中最内层的调用权重最高。
请考虑以下示例。 “Product Sales”度量值为“Sales[ProductID]”和“Product[ProductID]”之间的关系分配高权重,为“Inventory[ProductID]”和“Product[ProductID]”之间的关系分配低权重。
DAX
复制
Product Sales =
CALCULATE(
CALCULATE(
SUM(Sales[SalesAmount]),
USERELATIONSHIP(Sales[ProductID], Product[ProductID])
),
USERELATIONSHIP(Inventory[ProductID], Product[ProductID])
)
备注
如果 Power BI 检测到多个具有相同优先级和相同权重的路径,它将返回多义性路径错误。 在这种情况下,必须通过使用 USERELATIONSHIP 函数或通过删除或修改模型关系来影响关系权重,从而解决多义性问题。
性能首选项
以下列表对筛选器传播性能(从最快到最慢)进行了排序:
一对多的源组内关系
使用中间表实现的多对多模型关系,并且涉及至少一个双向关系
多对多基数关系
跨源组关系