SQL 最佳实践 - 可以依靠自动增量字段按时间顺序对行进行排序吗?

Posted

技术标签:

【中文标题】SQL 最佳实践 - 可以依靠自动增量字段按时间顺序对行进行排序吗?【英文标题】:SQL Best Practices - Ok to rely on auto increment field to sort rows chronologically? 【发布时间】:2010-09-16 20:58:10 【问题描述】:

我正在与一位客户合作,他希望将时间戳添加到一堆表中,以便他们可以按时间顺序对这些表中的记录进行排序。所有的表还有一个自动递增的整数字段作为它们的主键 (id)。

(简单)想法 - 节省开销/存储并依靠主键按时间顺序对字段进行排序。当然这可行,但我不确定这种方法在健全的数据库设计中是否可以接受。

优点:每条记录所需的存储空间更少,VO 类更简单,等等。

Con:它暗示了该字段的一个特征,一个简单的标识符,其定义并没有以任何方式定义或保证它应该/将会发挥这样的作用。

为了我的问题,假设数据库表定义是一成不变的。仍然 - 就最佳实践而言,这是否可以接受?

谢谢

【问题讨论】:

你如何看待一个单独的例如“序列”编号在您的设计中会更“合理”吗?我认为依靠自动编号是一个不错的选择 - 当然至少与您可能自己实施的任何其他“手动”流程一样健全和可靠。 正如您所注意到的“它暗示了一个特征”。除非它被定义,否则无论你“总是看到”什么行为都应该被认为是偶然的,并且通常在最坏的时候会发生变化。我之所以这么说是因为该原则广泛适用于您的问题以及任何其他问题。 auto_increment 只是记录的参考标记; datetime 支持回溯记录,因为 id 不会是连续的。 【参考方案1】:

您要求的是“最佳做法”,而不是“不可怕的做法”,所以:,您不应该依赖自动递增的主键来建立年表。有一天,您将要对数据库设计进行更改,但这会中断。我已经看到了。

默认值为GETDATE() 的日期时间列几乎没有开销(大约与整数一样多)并且(更好)不仅告诉您序列,还告诉您实际日期和时间,这通常原来是无价的。即使在列上维护索引也相对便宜。

这些天来,我总是将一个CreateDate 列数据对象连接到现实世界的事件(例如帐户创建)。

编辑添加:

如果确切的年表对您的应用程序至关重要,则您不能依赖自动增量或时间戳(因为无论分辨率有多高,总是存在相同的时间戳)。你可能不得不做一些特定于应用程序的东西。

【讨论】:

但是如果你使用 SQL Server 200x DATETIME 数据类型,你可能会得到几行具有相同日期时间值的行(因为它的“分辨率”是 3.33ms)并且你无法分辨时间顺序再从那里订购,要么..... @marc_s:真;实际上你可以总是同时拥有时间戳(除非你的计时器比你的数据库更快)。如果顺序如此重要,您必须在更深层次上构建它。 @marc_s 在您的专栏中使用 datetime2。 @Gabriel Guimarães:即使使用 Datetime2,您也不能 100% 确定您不会得到两个具有相同值的条目...... datetime 和 datetime2 只是不安全。 ... @marc_s 日期时间精度为 100 纳秒。如果您的时钟速度大于 10 mghz,您将只能在同一范围内获得两个事件。【参考方案2】:

对于 egrunin 的回答,更改这些行的持久性或处理逻辑可能会导致行以非顺序或不确定的方式插入到数据库中。您可以实现一个并行文件处理器,该处理器在线程完成转换后立即将一行扔到数据库中,这可能是在另一个线程完成处理文件中较早出现的行之前。使用 ORM 进行记录持久性可能会导致类似的行为; ORM 可能只维护一个等待持久性的对象图的“包”(无序集合),并在被告知“刷新”其对象缓冲区时随机抓取它们以将它们持久保存到 DB。

在任何一种情况下,相信自动增量列会告诉您记录进入系统的顺序是不好的。它可能会或可能不会告诉您记录他的数据库的顺序;这取决于数据库的实现。

【讨论】:

【参考方案3】:

您可以通过对 ID 列进行排序在短期内实现相同的目标。这会更好地添加额外的数据来实现相同的结果。我认为任何人查看数据表并知道当他们看到它是一个标识列时它是按时间顺序排列的,这不会让人感到困惑。

不过,我看到了一些缺点或限制。

如果有人重新播种该列,则按时间排序可能会混乱 如果没有其他数据,则无法确定日期期间的年表 如果系统接受新的非时间顺序数据,此设置会阻止您按时间顺序排序

根据对这些“限制”的实际评估,您应该能够提出适当的方法。

【讨论】:

相信我,一些聪明的人会过来说他想将 Identity 列更改为有意义的值,或者出于某种愚蠢的原因从不同的起点重新开始值。使用日期时间 @Roadie57,我认为“用户”的恶魔本质是不言而喻的 :) 我同意你的观点,但是,OP 确实说过假设数据库结构是“一成不变的”。更不用说他正在为一个客户工作,而不是一个可能愿意为这种“无聊”升级付费的雇主。 我让真实的生活经历妨碍了我的思考。我实际上已经有人过来说所有自动增量值都必须重新播种以从 1008000 开始,以便可以运行一些愚蠢的愚蠢报告而无需过滤除 id 列之外的任何内容【参考方案4】:

正如 Brad 指出的那样,自动递增 ID 会让您了解顺序,但要正确操作 - 如果您想知道添加内容的时间,请使用 datetime 列。然后,您不仅可以按时间顺序排序,还可以应用过滤器。

【讨论】:

【参考方案5】:

不要这样做。您永远不应依赖 ID 列的实际值。把它当作一个黑盒子,只对查找键有用。

您说“每条记录所需的存储空间更少”,但这有多重要?我们正在谈论的行有多大?如果您有 200 字节的行,那么另外 4 个字节可能不会有太大影响。

不要在没有测量的情况下进行优化。先让它正常工作,然后再优化。

【讨论】:

【参考方案6】:

@MadBreaker

如果您需要知道创建具有自动增量的列顺序的顺序,则需要分开一些事情,但是如果您想知道插入的日期和时间,请使用 datetime2。

如果您不允许更新或删除,则可以保证时间顺序,但如果您想控制选择的时间,则应使用 datetime2。

【讨论】:

【参考方案7】:

您没有提到您是在单个数据库上运行还是在集群上运行。如果您是集群的,请注意增量实现,因为您不能总是保证事情会按照您自然认为的顺序出现。例如,Oracle 序列可以缓存下一组值(取决于您的设置)并为您提供 1、3、2、4、5 排序的列表...

【讨论】:

以上是关于SQL 最佳实践 - 可以依靠自动增量字段按时间顺序对行进行排序吗?的主要内容,如果未能解决你的问题,请参考以下文章

多对多表 id 的最佳实践

架构师之路Learn Day7之Hive生产环境最佳实践

Mybatis plus通用字段自动填充的最佳实践总结

慢SQL治理最佳实践

在一定时间后自动更改 SQL 服务器记录的最佳实践?

Django:关于自动递增主键的最佳实践