SQL最佳实践 - 是否可以依赖自增字段对行进行按时间排序?

19

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

这个(简单)想法-节省开销/存储费用并依靠主键对字段进行时间排序。当然,这很有效,但我不确定这种方法是否在数据库设计方面可接受。

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

缺点:它暗示了该字段的一个特征,一个本来是简单标识符的字段,并且其定义方式并未以任何方式定义或保证其应/将如此运行。

假设就我的问题而言,数据库表定义已经确定。即使如此-从最佳实践的角度来看,这样做是否可接受?

谢谢


你认为单独使用“序列”号在设计中会更加“稳健”吗?我认为依赖自动编号是一个相当不错的选择 - 至少和你自己实现的任何其他“手动”过程一样可靠和坚实。 - marc_s
正如你所指出的,“它意味着一种特征”。除非定义清楚,否则无论你“总是看到”什么行为都应被视为偶然事件,并且通常会在最糟糕的时候发生变化。我之所以广泛地陈述这一原则,是因为它适用于各种情况,包括你的问题和其他任何问题。 - msw
auto_increment只是记录的一个参考标记;datetime支持过期记录,因为id不会连续。 - OMG Ponies
7个回答

16
您要求“最佳实践”,而不是“不那么糟糕的实践”,所以:不,您不应该依赖于自增主键来建立时间顺序。有一天,您会引入数据库设计更改,这将导致破坏。我见过它发生过。
一个默认值为GETDATE()的datetime列几乎没有任何开销(大约与整数相同),并且(更好的是)不仅告诉您序列而且告诉您实际日期和时间,这通常被证明是无价的。即使在列上维护索引也相对便宜。
现在,我总是在与真实世界事件(例如账户创建)相关联的数据对象中添加一个CreateDate列。
编辑后添加:
如果确切的时间顺序对您的应用程序至关重要,则不能依赖于自动递增或时间戳(因为始终可能存在相同的时间戳,无论分辨率多高)。您可能需要制作一些特定于应用程序的东西。

1
但是如果你使用 SQL Server 200x 的 DATETIME 数据类型,你可能会得到几行拥有完全相同日期时间值的记录(因为它的“分辨率”是3.33毫秒),那么你将无法从中推断出时间顺序。 - marc_s
@marc_s:没错;实际上你总是可以拥有同时的时间戳(除非你的计时器比你的数据库更快)。如果序列是如此关键,那么你必须在更深层次上构建它。 - egrunin
@marc_s 在你的列上使用datetime2。 - Gabriel Guimarães
@Gabriel Guimarães:即使使用Datetime2,也不能百分之百地确定不会得到两个具有相同值的条目...... datetime和datetime2都不是安全的选择.... - marc_s
@marc_s datetime的精度为100纳秒。只有当您的时钟速度大于10 mghz时,才能在同一范围内获取两个事件。 - Gabriel Guimarães
@Gabriel Guimarães:在SQL Server上,您可以同时从多个客户端应用程序收到多个请求 - 没有必要将时钟速度设置得这么高..... - marc_s

3
根据egrunin的回答,更改这些行的持久性或处理逻辑可能导致非顺序或不确定方式向数据库插入行。您可以实现并行文件处理器,该处理器在线程完成转换后立即将行抛到DB中,这可能会在另一个线程完成处理文件中较早出现的行之前发生。使用ORM进行记录持久化可能会导致类似的行为;ORM可能仅维护“包”(无序集合)的对象图,等待持久化,并在被告知“刷新”其对象缓冲区时随机获取它们以将它们持久化到DB中。
在任一情况下,信任自动增量列告诉您记录进入系统的顺序是错误的。它可能能够告诉您记录击中数据库的顺序,这取决于DB实现。

2
您可以通过按照ID列进行排序来在短期内达到相同的目标。这比添加额外的数据来实现相同的结果更好。当您看到它是一个身份标识列时,我不认为任何人会对数据表感到困惑,并知道它是按时间顺序排列的。
然而,我还是看到了一些缺点或限制:
- 如果有人重新种子列,时间顺序可能会被搞乱。 - 没有额外的数据,无法确定日期周期的时间顺序。 - 如果系统接受新的非时间顺序数据,则此设置将阻止您按时间顺序排序。
基于对这些“限制”的现实评估,您应该能够提供适当的方法建议。

相信我,总会有一些聪明人想要将标识列更改为有意义的内容或以某种愚蠢的原因从不同的起始点重新开始值。使用 DateTime。 - Roadie57
@Roadie57,我认为“用户”的恶魔性质是不言而喻的 :) 但是我同意你的观点,OP确实说要假设数据库结构是“一成不变”的。更不用说他是在为客户工作,而不是雇主,后者可能愿意支付这样“琐碎”的升级费用。 - Brad
我之前让真实生活经验影响了我的思维。实际上,有人告诉我所有自动递增的值必须重新起始值为1008000,这样才能运行某个愚蠢的报告而不需要通过任何过滤器来过滤除ID列以外的内容。 - Roadie57

1

自动递增的ID会给你一个顺序的概念,正如Brad所指出的那样,但要做到正确 - 如果你想知道什么时候添加了某个东西,就需要有一个日期时间列。这样你不仅可以按时间顺序排序,还可以应用过滤器。


0

不要这么做。您永远不应该依赖于ID列的实际值。将其视为黑匣子,仅用于执行关键查找。

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

不要在没有测量的情况下进行优化。首先将其正确地工作,然后再进行优化。


0

@MadBreaker

有两件不同的事情,如果你需要知道顺序,可以创建一个带有自动增量的列顺序,但是如果你想知道插入的日期和时间,应该使用datetime2。

如果不允许更新或删除,那么时间顺序可以得到保证,但如果你想要对选择进行时间控制,应该使用datetime2。


0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接