【问题标题】:Why is datekey in fact tables always INT?为什么事实表中的 datekey 总是 INT?
【发布时间】:2017-07-05 19:04:20
【问题描述】:

我正在查看AdventureWorksDW 中的事实表中的datekey 列,它们都是int 类型。

这是有原因的,而不是date类型的原因吗?

我了解创建由INT 组成的聚集索引将优化查询速度。但是,假设我想获取过去一周的数据。我可以从日期20170704 中减去 6,我会得到20170698,这不是一个有效的日期。所以我必须将所有内容都转换为date,减去,然后转换为int

现在我有一个外键约束来确保没有插入除 'YYYYMMDD' 之外的东西。 Date 类型没有必要。刚才,我想得到一些 6/28 和 7/4 之间的数据。我不能只从“20170703”中减去六个;我必须从 int 转换到日期。

这似乎很麻烦,而且好处不多。

谢谢。

【问题讨论】:

  • 您为什么认为int(4 字节)上的索引比date 数据类型(3 字节)上的索引更有效?
  • 这里有一些讨论made2mentor.com/2011/05/…
  • 使用代理键有一个重要的好处:如果您决定增加时间维度的粒度(例如,从几天到几小时),您可以轻松地这样做,而无需更改现有数据 (是的,我有这样做的数据仓库的经验)。请注意,我说的是 surrogate 键,而不是创造性地编码日期的 INT 键,我看不出它比实际的日期/时间类型有任何好处。

标签: sql-server ssis sql-server-2012 ssas data-warehouse


【解决方案1】:

是的,您可以使用 Date 数据类型并将其作为 Fact 和维度中的主键,您将在此过程中为自己节省一个字节。

然后您将不得不处理已记录但我们不知道日期的销售。然后怎样呢?在“正常”维度模型中,您定义 Unknown 代理值,以便人们知道有数据并且它可能有用但不完整。一个常见的约定是使其为零或处于负数领域。用整数很容易做到。

日期有点奇怪,因为我们通常使用智能键 - yyyymmdd。从调试的角度来看,无需查看您的维度即可轻松快速识别日期。

您不能设置无效日期。那怎么办?每个人都“知道”1899 年 12 月 31 日是“假”日期(或任何让你喜欢的东西),这一切都很好,直到有人胖手指一个日期并神奇地击中你的哨兵日期,现在你已经混合了有效的未知数仅输入错误的数据。

如果您使用智能钥匙进行日期计算,那么您做错了。您需要转到您的数据维度以正确解析值并使用了解日期逻辑的方法,因为除了月份长度和闰年计算等简单的事情之外,它是丑陋和讨厌的。

【讨论】:

  • 我买这个并不是一个的理由。在输入典型的商务日期时,胖指法1899-12-31 将很难做到。而且我不认为数据类型的使用应该基于数据输入错误的可能性。胖手指2017-07-01 而不是2017-06-01 很容易为什么胖手指一个未知的日期不再是一个问题?如果您真的想避免胖手指错误,那么也许您应该使用 Guid 而不是智能键(或者至少键间隔一定距离)当然没有人这样做。
  • 在我们的例子中,没有数据输入。我们从 Oracle 表中导入大量数据,并且保证日期是正确的,因为 Oracle 表中的列也是 DATE(7) 类型
【解决方案2】:

实际上,事实表与 DimDate 表有关系,如果您加入该表,您将获得更多用于时间点搜索的选项,如果您可以通过添加和删除天/月来获得。

假设您需要 5 月第二个星期六的所有订单清单?还是 12 月最后一周的所有订单? 还有一些企业对他们的会计年度的规定不同。有些从 6 月开始,有些从 1 月开始..

总之,当您需要在不进行任何计算的情况下进行复杂的日期搜索并在 DimDate 上使用简单的索引搜索时,DimDate 可为您提供灵活性

【讨论】:

  • 但是日期维度的主键可以是日期而不是整数。问题不是问日期维度的用途是什么,而是为什么将20170701 等整数用作键而不是为日期设计的数据类型。
  • 可能,使用自动生成的不断增加的整数而不是日期只是一种更好的做法。没有特别的原因
  • 所以这是“更好的做法”但“没有特别的原因”?这几乎不是一个令人信服的论点。为什么它是更好的做法?
  • 问题中的示例不是自动生成的。它使用一种明确定义的格式来编码日期并且会有间隙。例如从2017063020170701。无论如何,插入日期维度并不常见。
  • 日期列没有任何格式。它存储为 3 字节整数,没有任何格式。至于文字的字符串格式,只需使用 ISO 格式。 '2017-06-30'。与参数相比,文字很少见,并且选择更大的数据类型,因为您必须在文字中输入更少的字符,这似乎不是一个好的理由。并且查询处理器在解析过程中强制转换的开销是微不足道的。
【解决方案3】:

这是一个很好的问题,但答案取决于您的目标是哪种数据仓库。例如,SSAS 涵盖表格和多维。

在多维中,您永远不会通过 SQL 查询事实表本身,因此您注意到的问题例如从 20170704 中减去 6 天实际上永远不会出现。因为在 MD SSAS 中,您将在维度本身上使用 MDX 来实现日期逻辑(如上面@S4V1N 的回答中所建议的那样)。 Calendar.Date.PrevMember(6)。对于更复杂的东西,您可以构建各种日期层次结构并进入 MDX ParallelPeriod 和 FirstChild 之类的东西。

对于您打算与 SQL 一起使用的数据仓库,您的问题更为紧迫。我认为在那种情况下@S4V1N 的答案仍然适用:将您的日期逻辑限制在维度方面

  1. 因为那里已经实施(可能使用预建的日历和财务层次结构)。
  2. 因为您的逻辑将在少一个数量级的行上运行。

我很高兴事实表以 INT 样式的日期为键:但那是因为我使用 MD SSAS。可能是 AdventureWorksDW 最初是在考虑 MD SSAS 的情况下构建的(实际上表中使用的键是否适用于 SQL 无关紧要),尽管 MS 的重点似乎最近已转向表格 SSAS。或者,将 INT 用于日期键可能是“开发人员推动”的设计决策,旨在阻止对事实表本身的日期操作,而不是在日期维度上。

【讨论】:

  • 感谢您的回复。我们的数据库最初是一个关系数据库,由于需要报告,我正在测试 SSDT。但我肯定会使用常规 tsql 进行查询。
【解决方案4】:

线程很旧,但我的两分钱。

在我工作过的一个客户中,选择的设计是一个 int 列。给出的原因(由我加入之前的某个人)是从不同来源导入的 - 有些包含时间信息,有些只提供日期信息(开头都是字符串)。

通过使用 int 键,我们可以将日期/日期时间信息保留在 Fact 表的日期时间列中,同时拥有仅包含日期部分的第二列(数据类型:日期/日期时间)并使用它来加入 Dim 表。这样,(a)聚合/度量将更少涉及(b)我们不会过早丢弃时间信息,这可能在某些时候有价值,并且(c)在那个时候,如果需要,可以将日期维度重构为包括时间或可以创建新的 DateTime 维度。

也就是说,这是公认的权衡取舍,但可能不是普遍的建议。

【讨论】:

    【解决方案5】:

    现在是一个非常古老的线程,

    对于非日期列,顺序整数键被认为是最佳实践,因为它速度快,而且相当小。封装业务逻辑的自然键可能会随着时间的推移而改变,并且可能需要某种方法来识别该维度的哪个版本用于缓慢变化的维度。

    [https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/dimension-surrogate-key/][1]

    理想情况下,为了保持一致性,日期维度也应该有一个连续的整数键,那么为什么会有所不同呢?毕竟调试理论也可以应用于其他(非日期)维度。来自 The Data Warehouse Toolkit, 3rd Edition, Kimball & Ross, page 49 (Calendar Date Dimension) is this comment

    为了方便分区,日期维度的主键可以是 更有意义,比如表示 YYYYMMDD 的整数,而不是 一个按顺序分配的代理键。

    虽然我认为这意味着对事实表进行分区。我认为 datekey 是一个整数,以便与其他维度保持一致,但不是顺序键,以便更轻松地进行表分区。

    【讨论】:

    • 仍然可以解释为什么您不能使用自然日期数据类型“2020-01-15”。它的顺序与作为整数的递增日期相同,您当然可以使用普通日期进行分区
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 2016-02-26
    • 2022-11-03
    • 1970-01-01
    相关资源
    最近更新 更多