Microsoft Fabric 仓库中的维度建模:维度表

适用于:✅SQL 分析终结点和 Microsoft Fabric 中的仓库

注意

本文属于维度建模系列文章的一部分。 本系列重点介绍 Microsoft Fabric 仓库中与维度建模相关的指南和设计最佳做法。

本文提供了在维度模型中设计维度表的指南和最佳做法。 它为 Microsoft Fabric 中的仓库提供了实用指南,这是一种支持许多 T-SQL 功能的体验,比如创建表和管理表中的数据。 因此,你可以完全控制创建维度模型表并向其加载数据。

注意

在本文中,术语数据仓库是指企业数据仓库,该数据仓库可全面集成整个组织的关键数据。 相比之下,单独的术语仓库是指 Fabric 仓库,它是一种服务型软件 (SaaS) 关系数据库产品/服务,可用于实现数据仓库。 为清楚起见,后者在本文中被称为 Fabric 仓库

提示

如果你不熟悉维度建模,请考虑将此系列文章作为你的第一步。 本文并非旨在提供有关维度建模设计的完整讨论。 有关更多信息,请直接参考广泛采用的已发布内容,如 Ralph Kimball 等创作的数据仓库工具包:维度建模的最终指南(第三版,2013 年)。

在维度模型中,维度表描述与你的业务和分析要求相关的实体。 大致而言,维度表代表你建模的内容。 内容可以是产品、人员、地点或任何其他概念,包括日期和时间。 若要轻松识别维度表,通常要为其名称加上前缀 d_Dim_

维度表结构

若要描述维度表的结构,请考虑名为 d_Salesperson 的销售员维度表的以下示例。 此示例应用了良好的设计做法。 后续部分将介绍每一组列。

CREATE TABLE d_Salesperson
(
    --Surrogate key
    Salesperson_SK INT NOT NULL,
    
    --Natural key(s)
    EmployeeID VARCHAR(20) NOT NULL,
    
    --Dimension attributes
    FirstName VARCHAR(20) NOT NULL,
    <…>
    
    --Foreign key(s) to other dimensions
    SalesRegion_FK INT NOT NULL,
    <…>
    
    --Historical tracking attributes (SCD type 2)
    RecChangeDate_FK INT NOT NULL,
    RecValidFromKey INT NOT NULL,
    RecValidToKey INT NOT NULL,
    RecReason VARCHAR(15) NOT NULL,
    RecIsCurrent BIT NOT NULL,
    
    --Audit attributes
    AuditMissing BIT NOT NULL,
    AuditIsInferred BIT NOT NULL,
    AuditCreatedDate DATE NOT NULL,
    AuditCreatedBy VARCHAR(15) NOT NULL,
    AuditLastModifiedDate DATE NOT NULL,
    AuditLastModifiedBy VARCHAR(15) NOT NULL
);

代理键

示例维度表具有一个代理键,该键命名为 Salesperson_SK。 代理键是生成并存储在维度表中的单列唯一标识符。 它是一个主键列,用于与维度模型中的其他表相关联。

代理键努力将数据仓库与源数据中的更改隔离开来。 它们还提供许多其他益处,使你能够:

  • 合并多个数据源(避免重复的标识符冲突)。
  • 将多列自然键合并为更高效的单列键。
  • 使用渐变维度 (SCD) 类型 2 跟踪维度历史记录。
  • 限制事实数据表宽度以优化存储(通过选择最小的整数数据类型)。

代理键列是一种建议做法,即使自然键(如下所述)似乎是可接受的候选项。 还应避免为键值提供含义(日期和时间维度键除外,见稍后所述)。

自然键

示例维度表还具有一个自然键,该键命名为 EmployeeID。 自然键是存储在源系统中的键。 它允许将维度数据与其源系统关联,这通常由提取、加载和转换 (ETL) 进程来完成以加载维度表。 有时,自然键称为业务键,其值可能对商务用户有意义。

有时,维度没有自然键。 对于日期维度或查找维度,或者通过规范化平面文件生成维度数据时,都可能出现这种情况。

“维度属性”

示例维度表还具有维度属性,如 FirstName 列。 维度属性为存储在相关事实数据表中的数值数据提供上下文。 它们通常是分析查询中使用的文本列,用于筛选和分组(切片和切块),但不能自行合并。 一些维度表包含少数几个属性,而另一些则包含许多属性(尽可能多地支持维度模型的查询要求)。

提示

确定所需的维度和属性的一个好方法是找到合适的人员并提出合适的问题。 具体而言,对提到“按”这个词保持警惕。 例如,当有人说他们需要“按”销售员、“按”月和“按”产品类别分析销售时,他们的意思是需要具有这些属性的维度。

如果你计划创建 Direct Lake 语义模型,则应包含筛选和分组为维度属性所需的所有可能列。 这是因为 Direct Lake 语义模型不支持计算列。

外键

示例维度表还具有一个外键,该键命名为 SalesRegion_FK。 其他维度表可以引用外键,并且它们存在于维度表中是一种特殊情况。 它表示该表与另一个维度表相关,这意味着它可能构成 Snowflake 维度的一部分,或者与子维度相关。

Fabric 仓库支持外键约束,但无法强制执行它们。 因此,加载数据时,ETL 进程测试相关表之间的完整性非常重要。

创建外键仍然是一个好主意。 创建非强制外键的一个很好的理由是允许建模工具(如 Power BI Desktop)在语义模型中自动检测和创建表之间的关系。

历史跟踪属性

示例维度表还具有各种历史跟踪属性。 历史跟踪属性是可选的,取决于跟踪源系统中发生的特定更改的需要。 它们使存储值能够支持数据仓库的主要角色,即准确描述过去。 具体而言,当 ETL 进程将新的或更改的数据加载到维度时,这些属性将存储历史上下文。

有关详细信息,请参阅本文后面的管理历史更改

审核属性

示例维度表还具有各种审核属性。 审核属性是可选的,但建议使用。 它们使你能够跟踪创建或修改维度记录的时间和方式,并且可以包括 ETL 进程中产生的诊断或故障排除信息。 例如,你将要跟踪谁(或哪些进程)更新了行,以及何时进行的更新。 审核属性还可以帮助诊断具有挑战性的问题,例如 ETL 进程何时意外停止。 它们还可以将维度成员标记为错误或推断成员

维度表大小

通常,维度模型中最有用且最通用的维度是大而宽的维度。 在行数(超过数百万)方面,它们很,在维度属性的数量(可能数百个)方面,它们很宽。 大小并不是那么重要(尽管你应该设计和优化尽可能小的大小)。 重要的是,维度支持对事实数据进行所需的筛选、分组和准确的历史分析。

大维度可能源自多个源系统。 在这种情况下,维度处理需要组合、合并、删除重复数据并标准化数据:以及分配代理键。

相比之下,有些维度很小。 它们可能表示只包含几个记录和属性的查找表。 通常,这些小维度存储与事实数据表中的事务相关的类别值,它们以具有代理键的维度形式实现,以与事实记录相关。

提示

如果有多个小维度,请考虑将它们合并为杂项维度

维度设计概念

本节介绍各种维度设计概念。

非规范化与规范化

通常情况下,维度表应该是非规范化的规范化是用于描述以减少重复数据的方式存储的数据的术语,而非规范化则是用于定义预计算冗余数据的存在位置的术语。 冗余数据通常因层次结构(稍后讨论)的存储而存在,这意味着层次结构会平展。 例如,产品维度可以存储子类别(及其相关属性)和类别(及其相关属性)。

由于维度通常较小(与事实数据表相比),存储冗余数据的成本几乎总是被改进的查询性能和可用性所抵消。

雪花维度

非规范化的一个例外是设计 Snowflake 维度。 Snowflake 维度已规范化,它跨多个相关表存储维度数据。

下图描绘了一个 Snowflake 维度,其中包含三个相关的维度表:ProductSubcategoryCategory

图中显示了上一段所述的 Snowflake 维度的插图。

考虑在以下情况下实现 Snowflake 维度:

  • 维度极大,存储成本超过了高查询性能的需求。 (然而,定期重新评估发现这种情况仍然存在。)
  • 需要键才能将维度与更精细的事实数据相关联。 例如,销售事实数据表在产品级存储行,但销售目标事实数据表在子类别级存储行。
  • 需要在以更高级别的粒度跟踪历史更改

注意

请记住,Power BI 语义模型中的层次结构只能基于单个语义模型表中的列。 因此,Snowflake 维度应通过使用将 Snowflake 表联接在一起的视图来提供非规范化结果。

层次结构

通常,维度列会生成层次结构。 层次结构允许在不同的汇总级别浏览数据。 例如,矩阵视觉对象的初始视图可能显示年销售额,报表使用者可以选择向下钻取以显示季度和每月销售额。

可通过三种方法将层次结构存储在维度中。 可用工具如下:

  • 来自单个非规范化维度的列。
  • Snowflake 维度,其中包含多个相关表。
  • 维度中的父-子关系(自引用)。

层次结构可以是均衡的,也可以是不均衡的。 同样重要的是要明白一些层次结构是不规则的。

均衡层次结构

均衡层次结构是最常见的层次结构类型。 均衡层次结构具有相同的级别数。 均衡层次结构的一个常见示例是日期维度中的日历层次结构,该层次结构包含年份、季度、月和日期的级别。

下图描绘了销售区域的均衡层次结构。 它包括两个级别,即销售区域组和销售区域。

关系图显示了包含“组”和“销售区域”列的销售区域维度成员的表。

均衡层次结构的级别基于来自单个非规范化维度的列,或基于构成 Snowflake 维度的表。 当基于单个非规范化维度时,表示较高级别的列包含冗余数据。

对于均衡层次结构,事实数据始终与层次结构的单个级别相关,这通常是最低级别。 这样,事实数据就可以合并(汇总)到最高级别的层次结构。 事实数据可以与任何级别相关,这由事实数据表的粒度决定。 例如,销售事实数据表可能以日期级别存储,而销售目标事实数据表可能以季度级别存储。

非均衡层次结构

非均衡层次结构是一种不太常见的层次结构类型。 非均衡层次结构具有基于父-子关系的级别。 因此,非均衡层次结构中的级别数由维度行决定,而不是特定的维度表列。

非均衡层次结构的一个常见示例是员工层次结构,其中员工维度中的每一行都与同一表中的报表管理器行相关。 在这种情况下,任何员工都可以成为具有报告员工的经理。 当然,层次结构的一些分支将比其他分支具有更多的级别。

下图描绘了一个非均衡层次结构。 它包括四个级别,层次结构中的每个成员都是销售员。 请注意,销售员在层次结构中的上级数不同,具体取决于他们向谁报告。

关系图显示了包含“报告对象”列的销售员维度成员的表。

非均衡层次结构的其他常见示例包括物料清单、公司所有权模型和总帐。

对于非均衡层次结构,事实数据始终与维度粒度相关。 例如,销售事实数据与具有不同报告结构的不同销售员相关。 维度表将具有代理键(命名为 Salesperson_SK)和 ReportsTo_Salesperson_FK 外键列,其引用了主键列。 每个没有人要管理的销售员不一定在层次结构任何分支的最底层。 当他们不处于最低级别时,销售员可能会销售产品,并且还会具有也在销售产品的报告销售员。 因此,事实数据的汇总必须考虑各个销售员及其所有下级。

查询父-子层次结构可能很复杂和缓慢,尤其是对于大维度。 虽然源系统可能会将关系存储为父-子级,但建议将层次结构自然化。 在此实例中,自然化意味着将层次结构级别转换和存储到维度中作为列。

提示

如果选择不自然化层次结构,仍可以根据 Power BI 语义模型中的父-子关系创建层次结构。 但是,不建议对大维度使用此方法。 有关详细信息,请参阅了解 DAX 中父子层次结构的函数

不规则层次结构

有时,层次结构是不规则的,因为层次结构中的成员的父级存在于不紧随其上方的级别。 在这些情况下,缺失的级别值会重复父级的值。

请考虑均衡的地理层次结构的示例。 当国家/地区没有州或省时,存在不规则分级结构。 例如,新西兰既没有州也没有省。 因此,插入新西兰行时,还应将国家/地区值存储在 StateProvince 列中。

下图描绘了地理区域的不规则分级结构。

关系图显示了一个地理维度成员表,其中包括国家/地区、州/省/自治区/直辖市和市列。

管理历史更改

如有必要,可以通过实现渐变维度 (SCD) 来管理历史更改。 SCD 在加载新的或更改的数据时维护历史上下文。

以下是最常见的 SCD 类型。

  • 类型 1:覆盖现有的维度成员。
  • 类型 2:插入基于新时间的版本控制维度成员。
  • 类型 3:使用属性跟踪有限的历史记录。

维度可以同时支持 SCD 类型 1 和 SCD 类型 2 更改。

SCD 类型 3 不常用,部分原因是它很难在语义模型中使用。 认真考虑 SCD 类型 2 方法是否更合适。

提示

如果预计维度发生快速变化,它是具有频繁更改的属性的维度,请考虑改为将该属性添加到事实数据表。 如果属性是数值(如产品价格),则可以将其作为度量值添加到事实数据表中。 如果属性是文本值,则可以基于所有文本值创建维度,并将其维度键添加到事实数据表中。

SCD 类型 1

SCD 类型 1 更改将覆盖现有维度行,因为无需跟踪更改。 此 SCD 类型还可用于更正错误。 它是一种常见的 SCD 类型,应该用于大多数不断变化的属性,例如客户名称、电子邮件地址和其他属性。

下图描述了销售员维度成员在其电话号码更改时的前后状态。

关系图显示了销售员维度表的结构,以及单个销售员更改电话号码前后的值。

此 SCD 类型不会保留历史视角,因为现有行已更新。 这意味着 SCD 类型 1 更改可能会导致不同的更高级别合并。 例如,如果将销售员分配到其他销售区域,SCD 类型 1 更改将覆盖维度行。 然后,向区域汇总销售员的历史销售结果将产生不同的结果,因为它现在使用新的当前销售区域。 就好像该销售员总是被分配到新的销售区域。

SCD 类型 2

SCD 类型 2 更改会导致产生表示基于时间的维度成员版本的新行。 始终存在当前版本行,它反映源系统中的维度成员的状态。 维度表中的历史跟踪属性将存储值,这些值可用于标识当前版本(当前标志为 TRUE)及其有效期。 代理键必需的,因为存储多个版本时将存在重复的自然键。

它是一种常见的 SCD 类型,但应保留给必须保留历史视角的属性。

例如,如果将销售员分配到其他销售区域,SCD 类型 2 更改将涉及更新操作和插入操作。

  1. 更新操作将覆盖当前版本,以设置历史跟踪属性。 具体来说,将结束有效性列设置为 ETL 处理日期(或源系统中的合适时间戳)并将当前标志设置为 FALSE
  2. 插入操作会将新的当前版本、设置开始有效性列添加到结束有效期列值(用于更新以前的版本)且将当前标志添加到 TRUE

请务必了解相关事实数据表的粒度不在销售员级别,而是销售员版本级别。 将其历史销售结果汇总到区域将产生正确的结果,但将有两个(或更多)销售员成员版本需要分析。

下图描述了销售员维度成员在其销售区域更改时的前后状态。 因为组织想要根据销售员分配到的区域来分析他们的工作,所以它触发了 SCD 类型 2 的变更。

关系图显示了销售员维度表的结构,其中包括“开始日期”、“结束日期”和“当前”列。

提示

当维度表支持 SCD 类型 2 更改时,应包含描述成员和版本的标签属性。 假设 Adventure Works 的销售员 Lynn Tsoflias 将分配从澳大利亚销售区域更改为英国销售区域。 第一版本的标签属性可以读取“Lynn Tsoflias(澳大利亚)”,当前新版本的标签属性可以读取“Lynn Tsoflias(英国)”。如果有用,则可能还会在标签中包含有效日期。

应均衡历史准确性与可用性和效率的需求。 尝试避免对维度表进行过多的 SCD 类型 2 更改,因为它可能会导致大量的版本,这可能会使分析人员难以理解。

此外,版本过多可能表示更改的属性存储在事实数据表中可能更好。 对前面的示例进行延伸可知,如果销售区域更改频繁,则销售区域可以存储为事实数据表中的维度键,而不是实现 SCD 类型 2。

请考虑以下 SCD 类型 2 历史跟踪属性。

CREATE TABLE d_Salesperson
(
    <…>

    --Historical tracking attributes (SCD type 2)
    RecChangeDate_FK INT NOT NULL,
    RecValidFromKey INT NOT NULL,
    RecValidToKey INT NOT NULL,
    RecReason VARCHAR(15) NOT NULL,
    RecIsCurrent BIT NOT NULL,

    <…>
);

下面是历史跟踪属性的目的。

  • RecChangeDate_FK 列存储更改生效的日期。 你可以通过它查询更改发生的时间。
  • RecValidFromKeyRecValidToKey 列存储行的生效日期。 请考虑存储在 RecValidFromKey 的日期维度中找到的最早日期来表示初始版本,并为当前版本的 01/01/9999 存储 RecValidToKey
  • RecReason 列是可选的。 它可用于记录插入版本的原因。 它可以对更改的属性进行编码,也可能是来自源系统的说明特定业务原因的代码。
  • 通过 RecIsCurrent 列,可以只检索当前版本。 它在 ETL 进程在加载事实数据表时查找维度键时使用。

注意

某些源系统不会存储历史更改,因此必须定期处理维度以检测更改并实现新版本。 这样,就可以在更改发生后不久检测到更改,并且更改的有效日期将是准确的。

SCD 类型 3

SCD 类型 3 更改使用属性跟踪有限的历史记录。 当需要记录上次更改或大量的最新更改时,此方法非常有用。

此 SCD 类型保留有限的历史视角。 当只需要存储初始值和当前值时,它可能很有用。 在此实例中,不需要临时更改。

例如,如果将销售员分配到其他销售区域,SCD 类型 3 更改将覆盖维度行。 专门存储上一个销售区域的列将被设置为上一个销售区域,新的销售区域设将被设置为当前销售区域。

下图描述了销售员维度成员在其销售区域更改时的前后状态。 由于组织想要确定任何以前的销售区域分配,因此将会触发 SCD 类型 3 更改。

关系图显示了销售员维度表的结构,其中包含“以前的销售区域”和“以前的销售区域结束日期”列。

特殊的维度成员

你可以将行插入到表示缺失、未知、N/A 或错误状态的维度中。 例如,可以使用以下代理键值。

键值 用途
0 缺少(在源系统中不可用)
-1 未知(在事实数据表加载期间查找失败)
-2 N/A(不适用)
-3 错误

日历和时间

事实数据表几乎无一例外地存储特定时间点的度量值。 若要支持按日期(可能是时间)进行分析,必须有日历(日期和时间)维度。

源系统具有日历维度数据并不常见,因此必须在数据仓库中生成它。 通常,它只生成一次,如果它是日历维度,则在需要时可以使用将来日期对其进行扩展。

日期维度

日期(或日历)维度是用于分析的最常见维度。 它为每个日期存储一个行,并支持按特定日期周期(如年份、季度或月份)进行筛选或分组的常见要求。

重要

日期维度不应该包含扩展到一天中的时间的粒度。 如果需要一天中的具体时间分析,则应同时具有日期维度和时间维度(如后面所述)。 存储一天中的具体时间事实数据的事实数据表应有两个外键,每个外键对应一个维度。

日期维度的自然键应使用日期数据类型。 代理键应使用 YYYYMMDD 格式和 int 数据类型来存储日期。 当代理键值具有意义且人工可读时,此接受的做法应该是唯一的例外(与时间维度一起)。 以 int 数据类型存储 YYYYMMDD 不仅高效且以数字方式排序,而且符合明确的国际标准组织 (ISO) 8601 日期格式。

下面是要包含在日期维度中的一些常见属性。

  • YearQuarterMonthDay
  • QuarterNumberInYearMonthNumberInYear - 对文本标签进行排序可能需要它们。
  • FiscalYearFiscalQuarter – 一些公司计帐计划从年中开始,以便日历年开始/结束和会计年度不同。
  • FiscalQuarterNumberInYearFiscalMonthNumberInYear - 对文本标签进行排序可能需要它们。
  • WeekOfYear – 有多种方法可以标记一年中的具体一周,包括具有 52 或 53 周的 ISO 标准。
  • IsHolidayHolidayText – 如果你的组织在多个地理位置运营,你应该维护多组节假日列表,每个地理位置将其作为单独的维度或自然化到日期维度中的多个属性中。 添加 HolidayText 属性有助于识别要报告的节假日。
  • IsWeekday - 同样,在某些地理区域,标准工作周不是星期一到星期五。 例如,在许多中东地区,工作周是星期天到星期四,而其他地区则采用为期四天或六天的工作周。
  • LastDayOfMonth
  • RelativeYearOffsetRelativeQuarterOffsetRelativeMonthOffsetRelativeDayOffset – 支持相对日期筛选(例如上一个月)可能需要用到它们。 当前期间使用零的偏移量 (0):以前的周期存储偏移量 -1、-2、-3...未来周期存储偏移量 1、2、3....

与任何维度一样,重要的是它包含支持已知筛选、分组和层次结构要求的属性。 还可能存在将标签翻译成其他语言的属性。

当维度用于与更高粒度的事实数据关联时,事实数据表可以使用日期周期的第一个日期。 例如,存储季度销售员目标的销售目标事实数据表会将季度的第一个日期存储在日期维度中。 另一种方法是在日期表中创建键列。 例如,季度键可以使用 YYYYQ 格式和 smallint 数据类型来存储季度键。

维度应该用所有事实数据表使用的已知日期范围填充。 它还应包括数据仓库存储有关目标、预算或预测的事实数据时的将来日期。 与其他维度一样的是,可以包含表示缺失、未知、N/A 或错误情况的行。

提示

在互联网上搜索“日期维度生成器”,以查找生成日期数据的脚本和电子表格。

通常,在下一年年初,ETL 进程应将日期维度行扩展到未来的特定年份。 当维度包含相对偏移属性时,必须每天运行 ETL 进程,以根据当前日期(今天)更新偏移属性值。

时间维度

有时,事实数据需要存储在某个时间点(如一天中的具体时间)。 在这种情况下,创建时间(或时钟)维度。 它可以有分钟(24 x 60 = 1,440 行)甚至是秒(24 x 60 x 60 = 86,400 行)的粒度。 其他可能的粒度包括半小时或一小时。

时间维度的自然键应使用时间数据类型。 代理键可以使用适当的格式,并存储具有意义且人工可读的值,例如,通过使用 HHMMHHMMSS 格式。

下面是要包含在时间维度中的一些常见属性。

  • HourHalfHourQuarterHourMinute
  • 时间段标签(上午、下午、晚上、夜晚)
  • 工作班次名称
  • 高峰或非高峰标志

符合的维度

某些维度可能是一致性维度。 一致性维度与许多事实数据表相关,因此它们由维度模型中的多个星共享。 它们提供一致性,并且可帮助你减少正在进行的开发和维护。

例如,事实数据表通常至少存储一个日期维度键(因为活动几乎总是按日期和/或时间记录)。 因此,日期维度是一个常见的一致性维度。 因此,应确保日期维度包含与分析所有事实数据表相关的属性。

下面的关系图显示了 Sales 事实数据表和 Inventory 事实数据表。 每个事实数据表都与一致性维度 Date 维度和 Product 维度相关。

关系图显示了上一段所述的一致性维度的插图。

另一个示例是,员工和用户可以是同一组人。 在这种情况下,合并每个实体的属性以生成一个一致性维度可能有意义。

角色扮演维度

在当一个维度在事实数据表中被多次引用时,称为角色扮演维度

例如,当销售事实数据表具有订单日期、装运日期和交付日期维度键时,日期维度以三种方式关联。 每个方式都表示不同的角色,但只有一个实际日期维度。

下面的关系图描绘了 Flight 事实数据表。 Airport 维度是角色扮演维度,因为它作为 Departure Airport 维度和 Arrival Airport 维度与事实数据表有两次关联。

关系图显示了上一段所述的航空公司航班事实数据星型架构的插图。

杂项维度

如果有多个独立维度,特别是包含几个属性(可能只有一种)并且这些属性具有较低的基数(少数值)时,杂项维度非常有用。 杂项维度的目标是将许多小维度合并到单个维度中。 此设计方法可以减少维度数量,降低事实数据表键的数量,从而缩小事实数据表存储大小。 它们还有助于减少数据窗格的混乱,因为它们向用户提供的表较少。

杂项维度表通常会存储所有维度属性成员的笛卡尔积,具有代理键属性。

好的的候选项包括标志和指标、订单状态和客户人口统计状态(性别、年龄组和其他)。

下面的关系图描绘了一个名为 Sales Status 的杂项维度,它合并了订单状态值和交付状态值。

关系图显示订单状态和交付状态值,以及这些值的笛卡尔乘积如何创建“销售状态”维度行。

退化维度

当维度与相关事实数据的粒度相同时,可能会发生退化维度。 退化维度的常见示例是与销售事实数据表相关的销售订单号维度。 通常,发票编号是事实数据表中的单个非分层属性。 因此,不复制此数据来创建单独的维度表是可接受的做法。

下面的关系图描绘了 Sales Order 维度,它是基于销售事实数据表中的 SalesOrderNumber 列的退化维度。 此维度作为检索不同的销售订单号值的视图实现。

关系图显示了上一段中所述的退化维度。

提示

可以在 Fabric 仓库中创建视图,以便将退化维度呈现为用于查询目的的维度。

从 Power BI 语义建模的角度来看,可以使用 Power Query 将退化维度创建为单独的表。 这样一来,语义模型将符合最佳实践,即用于筛选或分组的字段源自维度表,用于总结事实数据的字段源自事实数据表。

子维度

当某个维度表与其他维度表相关时,它被称为子维度。 子维度有助于符合和重复使用维度模型中的定义。

例如,你可以创建一个地理维度,用于存储每个邮政编码的地理位置。 然后,客户维度销售员维度可以引用该维度,它们将存储地理维度的代理键。 这样,就可以使用一致的地理位置对客户和销售员进行分析。

下面的关系图描绘了一个 Geography 维度,该维度是子维度。 它不直接与 Sales 事实数据表相关。 相反,它通过 Customer 维度和 Salesperson 维度间接关联。

关系图显示了上一段所述的子维度的插图。

考虑当其他维度表属性存储日期时,日期维度可以用作子维度。 例如,客户维度中的出生日期可以通过使用日期维度表的代理键来存储。

多值维度

当某个维度属性必须存储多个值时,需要设计多值维度。 通过创建网桥表(有时称为联接表)来实现多值维度。 网桥表存储实体之间的多对多关系。

例如,假设有一个销售员维度,并且每个销售员都分配给一个或多个销售区域。 在这种情况下,创建销售区域维度是有意义的。 该维度只将每个销售区域存储一次。 一个单独的表(称为网桥表)为每个销售员和销售区域关系存储一行。 从物理上看,销售员维度到网桥表之间存在一对多关系,销售区域维度与网桥表之间存在另一个一对多关系。 从逻辑上看,销售员与销售区域之间存在多对多关系。

在下图中,Account 维度表与 Transaction 事实数据表相关。 由于客户可以有多个帐户,并且帐户可以有多个客户,因此维度表通过 Customer Account 网桥表关联。

关系图显示了上一段所述的多值维度的插图。

在本系列的下一篇文章中,了解事实数据表的指南和设计最佳做法。