【问题标题】:Surrogate key for date dimension?日期维度的代理键?
【发布时间】:2012-08-25 21:17:26
【问题描述】:

有两种思想流派:

  1. 使用代理键,最好采用以下格式:YYYYMMDD,因为这将始终 顺序。

  2. 删除日期维度代理键并改用实际日期。

我对维度建模专家的问题是:

1> Which design would you prefer and why?

2> How should we handle unknown values in each of the cases, Can we simply place 
   NULL in Fact table for unknown dates as Foreign Key can be NULL (if not why)?

3> If we need to partition fact table on date column, how would we achieve that 
   in case 1.

我倾向于在事实表中使用实际日期并使用 NULL 来表示 UNKNOWN 日期,因为无需查看维度表即可对事实进行与日期相关的验证。

【问题讨论】:

  • 你为什么要毁掉一个完美的约会?问题是:“这将始终是连续的”是什么意思?通过将密钥转换为 YYYYMMDD 可以实现什么
  • 不,我不会,但一个学派说为每个维度添加代理键并为 UNKOWN 日期添加不切实际的值。这篇文章只是为了评估每个案例的优点。
  • 不,我不会,但一个学派说为每个维度添加代理键并为 UNKOWN 日期添加不切实际的值。这种 YYYYMMDD 形式的优点是,代理键是直接从日期派生的,不需要任何查找。这篇文章只是为了评估每个案例的优点。
  • 我很确定日期也是连续的。

标签: oracle database-design oracle11g data-modeling


【解决方案1】:

Oracle 的不寻常之处在于其Date data type 包含时间,并且占用7 个字节。其他平台通常对裸日期有独立的数据类型。 SQL Server 的日期占用 3 个字节,PostgreSQL 占用 4 个字节,DB2 占用 4 个字节(我认为)。

当您使用格式为 YYYYMMDD 的整数时,您必须在某处编写附加代码以确保这些值是有效日期。 20121332 是一个有效的整数,但它不代表一个有效的日期。您不必为日期数据类型编写类似的验证代码。

当谈到在单列中记录缺失的信息时,这两种选择之间没有太大的区别。您要么使用不代表其他日期含义的日期,要么使用不代表其他整数含义的整数。用少量编码原因(例如,其中“1”可能表示“尚未提供”)意味着您必须将不是有效日期整数的值存储在同一列中有效的日期整数。

但我认为将丢失某些数据的事实与丢失数据的原因分开更有意义。这意味着存储更多数据,而有些人不愿意存储更多数据。


我发现这两本 IBM 红皮书对设计数据仓库很有用。

Anchor modeling 是最近的发展。以这种方式设计的架构中的大多数表都将位于6NF

【讨论】:

  • +1 更不用说你给 CBO 带来的问题等等。
  • “这意味着存储更多数据,有些人不愿意存储更多数据”。维度中只有 4 条左右的记录:-1 'Unknown',-2,'Early Date' -3 'Late Date' -4 'Not Yet Received'。不需要太多额外的数据来为用户增加更多的灵活性和实用性。
  • @Steve:还有很多复杂性。这样您就可以在同一列中存储两种不同类型的数据。
  • 我只在列中存储整数。 -4、-3、-2、-1、1、2 3 等。简单。标题“未知”位于单独的列中。
  • 不,4 没有任何意义。你必须加入维度才能看到 4 的含义,假设我的日历从 1908 年 1 月 1 日开始,它意味着 1980 年 1 月 4 日。它将如何影响汇总事实? ETL 将构建聚合事实,并且不会使用聚合函数,并且日历的 4 个“未知”成员将拥有他们的摘要记录,就像日历中的真实日期一样。我们在这里谈论的是数据集市——数据集市的重点是为用户提供快速、丰富和灵活的报告。当然,我们的工作就是处理复杂性,让用户的报告变得更简单。
【解决方案2】:

按照您的要求:

  1. Kimball 大谈特谈日期的代理键,但我还没有看到有说服力的技术论据支持这样做。转换为 YYYYMMDD 格式意味着您必须转换日期或加入日期维度以进行日期算术。这两种方法都有多种方式可以通过查询计划来解决。
    日期时间在 SQL Server 上是 8 个字节,在 Oracle 上是 (IIRC) 7 个字节,所以它比整数代理宽一点,但我不知道除非您拥有非常大的数据量,否则您将不再看到此论点的优点。优化器只是在幕后将日期视为数值。

  2. 我对一种或另一种类型的“特殊”值有要求。根据您希望它们如何排序,您可以使用各种值。过去我曾多次使用此方案:

    • 1800-01-01 表示“以前的”。除非您需要比这更早的日期,否则这将在开头排序。
    • 9000-01-01 表示“正在进行”。这将在最后进行排序。
    • 9100-01-01 表示“未知”。这将在最后进行排序。
    • 9200-01-01 表示“错误”。这将在最后进行排序。
  3. 范围分区在任何支持它的 DBMS 平台(包括几乎所有主流 RDBMS 平台)上都可以在日期或整数分区键上正常工作。

我不建议对数据仓库中的未知值使用 NULL,因为它需要外部连接才能使用数据。这将影响查询计划的效率,并为没有经验的玩家设置数据陷阱。数据仓库中的 NULL 键在很多方面都不好。

NULL 键值的另一个问题是大多数临时报告工具不能很好地使用连接中的空键。通常它们会使用内部连接,因此键列中带有 NULL 的行会中断。

对于大多数其他维度,您将使用代理项。这将维度与源数据分离,并允许您将新数据源引入系统,而不会破坏现有数据。

在某些情况下,将自然键用作维度键可能很有用。这方面的一个例子可能是 ISO 货币代码或帐号。在前一种情况下,3 个字母的代码足够小,因此将其用作密钥的开销最小,并且编码方案(通常)在所有数据源中都是通用的。在后一种情况下,代码通常是数字且足够短以适应整数,并且通常在整个组织中通用。

这样做的主要好处是您可以让报告专家使用他们自己的查询来处理数据。它使表格对于直接使用数据的人来说更清晰。

【讨论】:

  • 您对产品维度使用代理项吗?
  • 您确实需要代理键来处理缓慢变化的尺寸,我更喜欢保持一致。用户如何知道 •1800-01-01 表示先前,而 9200-01-01 表示错误。很确定用户会希望我的解决方案在维度中有一些额外的行来覆盖这一点。我想您可以拥有以 9200-01-01 作为键的附加行。
  • @Steve - “日期”从来都不是一个缓慢变化的维度。您可以在“DisplayDate”列中为特殊值添加日期维度中的行,该列中包含其他日期的漂亮打印日期。
  • 不,我知道日历不能移动,但其他人可以,所以我使用代理,所以为什么要使用日历例外。那是我的观点。对我来说,主要受众是报表用户,而不是分析师,而且我通常与拥有大量记录的银行合作,因此使用自然键看似很小的费用成本却被庞大的数量放大了。顺便说一句,我也不是 Kimball 狂热分子!
  • @Steve - 您可以对日期进行日期算术运算,但必须从 YYYYMMDD 转换为日期的查询可能无法进行 sarg。在某些情况下,必须加入日期维度会使查询复杂化。 (例如,查找 xxx 的所有实例,其中 yyy 的最新实例在它之前的 30 到 60 天之间)。
【解决方案3】:

1.最好使用 YYYYMMDD 格式的代理键,因为这将始终是连续的。

2.去掉日期维度代理键,改用实际日期。

使用第一个选项。您使用实际日期,它将占用更多磁盘,索引效率较低,连接效率较低。另外,如果您使用日期类型,您将如何表示“未知日期”、“日期尚不可用”、“日期早于日历日期范围”、“日期晚于日历日期范围”?

您不能对日历维度的所有这些不同的“未知”类型成员使用“01-01-1900”。理想情况下,所有代理键都应该是无意义的,否则报表用户太容易忽略维度。维度增加维度的丰富性,例如日历维度、日期所属的星期、月份、年份、日期名称等。应通过匿名代理键强制记者使用维度。

你不应该在数据仓库的表示层中有空值,因为它们会迫使你在事实和维度之间进行左外连接。星型模式的全部意义在于提高查询性能——进行外连接直接违背了这一原则。始终用 -1、-2 等未知成员键替换空值(假设您的“真实”成员键从 1 开始并按顺序从那里上升)。

为 Catcall 编辑

我建议使用代理键,其中日历中最早的日期获取密钥 1,下一个日期获取 2,依此类推。在星型模式中,事实由代理键组成 - 所有小整数或度量。您必须加入维度才能查看日期 1 代表什么。所有的代理人都没有任何意义。这就是您构建数据集市的方式。用户应该如何记住“01-01-1900”表示“日期不可用”和“01-01-1901”表示“未知”和“01-01-1902”早期日期等?将这些标题存储在维度中并实际上具有代理项-3、-2、-1 不是更好吗?然后用户将在报告中看到标题“未知”或“早期日期”。将日期类型用作代理键只是一个错误,并且会限制解决方案的实用性、效率和灵活性。我通过经验知道这一点。

【讨论】:

    猜你喜欢
    • 2016-03-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    • 1970-01-01
    相关资源
    最近更新 更多