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


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

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

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

Con:它暗示了该字段的特征,即一个简单的标识符,其定义不以任何方式定义或保证它应该/将如此起作用。

假设为了我的问题,DB表定义是一成不变的。仍然 - 这在最佳实践方面是否可以接受?

谢谢


12180
2017-09-16 20:58


起源

您如何看待另一个例如“序列”号在你的设计中会更加“健全”吗?我认为依靠自动编号是一个非常好的选择 - 当然至少与你自己可能实现的任何其他“手动”过程一样健全。 - marc_s
正如你所说,“这意味着一个特征”。除非它被定义,否则无论你“总是看到”什么行为都应该被认为是偶然的,并且通常在最糟糕的时候可能会发生变化。我对此作了广泛的陈述,因为该原则广泛适用于您的问题以及任何其他问题。 - msw
auto_increment只是记录的参考标记; datetime支持回溯记录,因为id不是顺序的。 - OMG Ponies


答案:


你要求“最佳实践”,而不是“不可怕的做法”,所以: 没有,您不应该依赖自动增量主键来建立年表。有一天你要引入数据库设计的改变,这将会破坏。我已经看到它发生了。

日期时间列,其默认值为 GETDATE() 具有非常小的开销(大约和整数一样多)并且(更好地)告诉你不仅仅是序列而且 实际日期和时间,这往往是无价的。即使在柱上保持索引也相对便宜。

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

编辑添加:

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


8
2017-09-16 21:41



但是如果你使用SQL Server 200x DATETIME 数据类型,你最终可能会有几行具有相同的日期时间值(因为它的“分辨率”是3.33毫秒),你不能再按时间顺序告诉它,要么..... - marc_s
@marc_s:true;实际上你可以 总是 具有同步时间戳(除非您的计时器比数据库更快)。如果序列是至关重要的,那么你必须在更深层次上构建它。 - egrunin
@marc_s在列上使用datetime2。 - Gabriel Guimarães
@GabrielGuimarães:即使使用Datetime2,你也不能100%确定你没有得到两个具有相同值的条目...... datetime和datetime2只是不安全.... - marc_s
@marc_s日期时间精度为100纳秒。如果您的时钟速度大于10 mghz,您将只能在同一范围内获得两个事件。 - Gabriel Guimarães


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

然而,我看到了一些缺点或限制。

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

基于对这些“限制”的现实评估,您应该能够建议正确的方法。


2
2017-09-16 21:05



请相信我,一些明智的人会说,他希望将Identity列更改为有意义的内容,或者出于某种愚蠢的原因从不同的起点重新启动值。使用DateTime - Roadie57
@ Roadie57,我认为“用户”的恶魔本质不言而喻:)我确实同意你的看法,然而,OP确实说假设数据库结构是“一成不变”。更不用说他正在为一个人工作 客户而不是可能愿意为这种“无聊”升级付费的雇主。 - Brad
我让现实生活中的经历妨碍了我的思考。我实际上已经有人过来说并且必须重新启动所有自动增量值以从1008000开始,这样一些愚蠢的愚蠢报告可以运行而不会被除了id列以外的任何内容过滤 - Roadie57


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

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


2
2017-09-16 21:52





自动递增ID将让您了解布拉德指出的订单,但做得正确 - 如果您想知道何时添加了某些内容,请使用日期时间列。那么你不仅可以按时间顺序排序,还可以应用过滤器。


1
2017-09-16 21:09





不要这样做。您永远不应该依赖ID列的实际值。像黑盒一样对待它,只对键查找有用。

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

没有测量就不要优化。首先让它正常工作,然后进行优化。


0
2017-09-16 22:03





@MadBreaker

如果您需要知道使用自动增量创建列顺序的顺序,则需要单独处理,但是如果您想知道插入的日期和时间,则使用datetime2。

如果您不允许更新或删除,则可以保证按时间顺序排列,但如果您希望时间控制为select,则应使用datetime2。


0
2017-10-07 14:12





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


0
2017-10-07 14:19