数据库设计 - 是不是应将日期用作主键的一部分

Posted

技术标签:

【中文标题】数据库设计 - 是不是应将日期用作主键的一部分【英文标题】:Database design - Should a Date be used as part of a primary key数据库设计 - 是否应将日期用作主键的一部分 【发布时间】:2010-09-25 08:36:28 【问题描述】:

将日期字段作为主键的一部分有哪些优点/缺点?

【问题讨论】:

【参考方案1】:

考虑一个零件库存表——如果您想在每天结束时存储库存水平,那么 part_id 和 date_of_day 上的复合主键就可以了。您可以选择将其设为唯一键并添加合成主键,特别是如果您有一个或多个表使用外键约束引用它,但除此之外,没问题。

所以它不一定有问题,但就像任何其他方法一样,它可能会被错误地使用,就像帕特里克的例子一样。

编辑:这是要添加的另一条评论。

我想起了我不久前写的关于数据库中的日期值是真的是自然的还是合成的。日期的可读表示为“YYYY-MM-DD”当然是自然的,但在 Oracle 内部,它存储为一个数字,仅代表 Oracle 的特定日期/时间。我们可以随时选择和更改该内部值的表示形式(以不同的可读格式,或完全不同的日历系统),而内部值不会失去其作为那个特定日期和时间的意义。我认为在此基础上,DATE 数据类型介于自然和合成之间。

【讨论】:

【参考方案2】:

我可以将它作为密钥的一部分,但要补充一点,您还应该将自动递增的序列号作为 PK 的一部分,并强制将任何日期作为 UTC 写入数据库,使用下游系统而不是转换为本地时间。

我工作过的一个系统决定,每当触及另一个表时,让 Oracle 触发器写入数据库,并使 sysdate 成为没有序列号的主键的一部分,这将是一个伟大的想法。唯一的问题是,如果您运行的更新查询每秒多次访问该行,它会破坏记录更改的表上的主键。

【讨论】:

UTC 方面的 +1。我们的数据库不使用 UTC,这给我们带来了痛苦。【参考方案3】:

如果您已经决定使用“自然”主键,那么问题是:日期是否是主键的必要部分 - 利弊无关!

【讨论】:

完全正确。任何其他的考虑都是无关紧要的。它要么在逻辑上适合区分唯一性,要么不适合。如果是这样,要么它在自然 PK 中,要么它应该处于替代唯一性约束中。它几乎不会在 FK 中有用。 嗯...永远不会在 FK 中有用?如果您 PK 包含它,则必须在 FK 中。没有用与否的选择,就是这样。随身携带复合键当然更难,但它非常有效,它很有效。【参考方案4】:

关于使用日期作为主键的一部分,我想问一些问题。

日期是否包括时间部分?这使事情变得棘手,因为时间包括时区和夏令时。这不会更改日期/时间值,但可能会在基于查询的排序或检索值方面产生意外结果。

我非常相信使用代理键(即使用序列列作为主键)而不是自然键(如使用日期)。

【讨论】:

【参考方案5】:

一个小小的缺点是它不像其他标识符那样优雅

(例如,对同事说请你看看记录 475663 比说请你看看 2008-12-04 19:34:02 更容易)

在不同区域设置不同的日期格式也存在混淆的风险

(例如,2008 年 3 月 4 日 - 欧洲 2008 年 4 月 3 日,美国 2008 年 3 月 4 日)

(我的偏好总是使用单独的键列)

【讨论】:

ISO 日期格式 YYYY-MM-DD 震撼! :) 作为在美国工作的英国人,我一直把它作为妥协的立场,因为即使在 10 年后,MM/DD/YYYY 也会像指甲划过黑板一样刺激我的神经。【参考方案6】:

一如既往..这取决于。

您在 PK 中包含日期/时间列的目的是什么?是否提供有关记录的附加信息而无需实际选择行?

我可以预见的主要问题是显而易见的问题,即您使用 UTC 日期还是本地日期?日期是否会被误解(有人会认为它表示当地时间,而它表示 UTC)?正如其他一些人所建议的那样,这可能会更好地用于代理/复合键?在主键以外的键或索引中使用它可能会更好地提高您的性能。

[旁注] 这让我想起了 (1) COMB(组合 GUID)背后的理论,尽管这里的想法是为 SQL Server 更好地索引/需要更少索引重建的 PK 创建唯一 ID,而不是将任何有意义的日期/时间值添加到一行。

(1) [http://www.informit.com/articles/article.aspx?p=25862&seqNum=7]

【讨论】:

【参考方案7】:

日期是非常好的主键,只要它们作为自然键的一部分有意义。我会在如下表格中使用日期:

holiday_dates(hol_date 日期) employee_salary(employee_id 整数,sal_start_date 日期)

(在上面添加代理employee_salary_id 有什么意义?)

对于某些表,可以使用日期,但其他更有意义的作为主键,例如:

hotel_room_booking (booking_reference)

我们本可以使用 (room_no, booking_from_date) 或 (room_no, booking_to_date),但参考对于与客户等进行沟通更有用。我们可能会将这些设置为 UNIQUE 约束,但实际上我们需要更复杂的“no重叠”检查这些。

【讨论】:

【参考方案8】:

日期作为主键的唯一或第一个组成部分会导致插入次数过多的表出现性能问题。 (表需要经常重新平衡)。

如果每个日期插入多个,通常会导致问题。

在大多数情况下,我认为这是一种难闻的气味,并建议不要这样做。

【讨论】:

【参考方案9】:

这并没有什么特别的问题,但正如其他海报所指出的那样,您可能会遇到时区和当地人的问题。此外,您最终可能会使用大量 DATE() 函数来混淆您的 SQL。

如果它类似于前面提到的一天结束时的库存,您也许可以考虑将一个八字符的文本字段(如“20081202”)作为主键的第二部分。这避免了时区区域设置问题,并且在需要时很容易转换为实际日期。

请记住,主键有两个功能来唯一标识记录和强制唯一性。代理主键也不行。

【讨论】:

唯一性与唯一性索引一样容易实施。代理键在连接中通常要快得多。而且很少有现实生活中的数据具有真正的自然唯一键(在为审计机构工作时,通过查询涉及数百个不同业务功能的数千个数据库)。 我理解关键列中的“日期”是指与时间无关的名义日期。这就像支票日期或发票日期。人们总是回溯。计划于 2005 年 12 月 2 日晚上 11:50 的航班应保持相同的日期以便查询,即使晚点 15 分钟起飞。【参考方案10】:

可能很难参考。我遇到了 _ID + _Date 作为复合 PK。这个复合键也是另一个表中的引用/FK。

首先,这纯粹是令人困惑,因为有 _ID 表示非复合键。

其次,对主表的插入是使用 SYSDATE 完成的,需要计算出该 SYSDATE 中的精确时间。 当你引用它时,你需要准确地知道其中的时间。否则它将不起作用......

【讨论】:

【参考方案11】:

使用日期作为主键的一部分可能会使表上的连接显着变慢。如果需要,我更喜欢代理键,然后是日期的唯一索引。

【讨论】:

您确定这一点 - 您是否进行了基准测试? Oracle DATE 保存在 7 个字节中 - 在 JOIN 中进行比较几乎不费力。 加入速度并不是选择代理键的充分理由。我赞同 Tony 关于基准的评论。

以上是关于数据库设计 - 是不是应将日期用作主键的一部分的主要内容,如果未能解决你的问题,请参考以下文章

数据库设计和非数字主键的使用

用不同的值替换也用作外键的主键

数据库设计和非数字主键的使用

是否可以按主键的一部分对 DQL 查询进行分组并返回具有 max() 日期时间记录(早于参考日期)的记录?

数据库主键

数据库中主键和外键的作用?