为多对多关系设计星型模式

hqt*_*hqt 4 data-warehouse database-design star-schema

从生产数据库构建DW星型模式设计的步骤/规则是什么?具体来说,您如何处理多对多关系。

我了解如何获取包括多对多关系在内的基本数据,并获得规范化的生产数据库:

例如:

如果我想处理销售交易,给表Product EntityPromotionEmployee中,第一步是建立一个表,SaleTransaction

SaleTransaction
- TransactionID
- ProductID
- EmployeeID
- SellingDateID
- Quantity
- SaleAmount
- PromotionID
Run Code Online (Sandbox Code Playgroud)

Promotion实体将是:

Promotion
- PromotionID
- ProductID
- DiscountAmount
Run Code Online (Sandbox Code Playgroud)

但是,这将只允许每次销售交易 1 个产品和 1 个促销活动。由于我们希望允许一种或多种产品以及零个或多个促销:

将生产 DB 设计转换为 DW 星型模式设计的等效步骤是什么?

Jon*_*des 6

多对多表通常使用“桥接表”处理。这实际上只是您在事务数据库中使用的多对多表的另一个名称:一列用于第一个表的 FK,一列用于第二个表的 FK,可能还有一两列用于家政领域。

您可能还需要Weight桥接表中的一个字段,其值等于 1 除以每次销售的条目数。当您想要避免重复计算具有多个促销活动的订单时,这让我们计算SUM(Weight)而不是COUNT(*)

你提出的模式很好,但我认为它可以稍微改进;想到两件事。其中之一是,我一般会崩溃SalesTransactions,并SalesTransactionDetails到一个表。这为客户 ID 之类的东西引入了冗余,这应该会让您的 OLTP 直觉退缩(从规范化数据库过渡到数据仓库是一种范式转变!),但在这种情况下,这是值得的。通过将您的所有销售额放入一个表中,您可以简化连接,并且在许多数据库中表明您想要使用位图索引。在仓库中,您通常最终不得不进行表扫描,但这没关系,因为您的事实表非常窄,并且适合内存。

所以我们有三个表SalesPromotions, 和SalesPromotions。您可能会考虑“订单”而不是“销售”,因为后者意味着可能不适用的最终确定性。如果您的系统包含已下达但未发货或未关闭的订单,则更通用的术语更有意义。这是在狡辩,但仔细考虑你给事物命名的东西从来没有坏处。

CREATE TABLE Orders
    -- IDs/dimensions:
    OrderID
    EmployeeID
    ProductID
    -- Date dimensions: date placed, date contract signed, date shipped, etc.
    -- Metrics: quantity, gross price, net price, extended price
    -- Attributes: is taxable, currency code, business key

CREATE TABLE Promotions
    PromotionID
    -- Date dimensions: date effective, date expires
    -- Metrics: fixed amount, percentage amount
    -- Attributes: name, type

CREATE TABLE OrderPromotions
    OrderID
    PromotionID
    Weight
Run Code Online (Sandbox Code Playgroud)

ExtendedPrice可以是计算列而不是存储值。如果属性开始使您的Orders表膨胀,请考虑使用“垃圾维度”

您可以包含ProductID在 中Promotions,但前提是促销只适用于单个产品。例如,您是否有一些适用于整个订单而不是特定订单项的促销活动?促销是否适用于今天的产品代码 ABC1,但明天在价格更改后适用于产品代码 ABC2?

我想到的第二个警告是 ID。我强烈建议您在数据仓库中使用合成密钥 (SK),而不是依赖来自源系统的 ID。有很多原因,这在 DBA.StackExchange 上的其他地方进行了讨论,但随意:

  1. SK 的 32 位或 64 位整数通常比源系统订单 ID 或客户 ID(例如,144 位 Salesforce ID 或其他长字母数字 ID)窄。这使您的表格变窄,您的二级索引变窄,并且您的扫描速度更快。
  2. 您可以避免源系统中的冲突。如果某天 Marketing 决定将产品密钥 ABC123 用于与去年无关的事情,您可以为他们提供两个不同的合成密钥。
  3. 特别是,如果您的公司收购了另一家公司,您可能会发现他们的 ID 与您一直使用的数据类型不匹配。您需要将它们映射到一个公共集合,并处理冲突。最好从第一天起就拥有相应的基础设施。
  4. 您可以将魔术值用于与报告相关但不在事务系统中处理的特定含义。例如,我总是将 SKs -1 用于“N/A”,将 0 用于“Unknown”。例如,Customers.FirstOrderSK对于没有订单的客户,该字段将填充 -1,对于有订单但尚无更多具体信息的客户,字段将填充 0。您的报告可以反映这一点,而无需放入特殊逻辑来处理 NULL 值。

您可以通过为没有促销的订单添加“虚拟记录”来利用桥表中的合成键。用PromotionID-1填充它,表示没有应用促销;现在,您的数据的消费者可以过滤以全价出售的订单。