IDENTITY和GetDate乱序

时间:2015-05-18 10:53:21

标签: sql-server identity getdate

我有一个表,其中包含IDENTITY列和GetDate()设置的DateTime列,如下所示:

CREATE TABLE [MyTable](
  [Id] [int] IDENTITY(1,1) ,
  [InsertTime] [datetime]  DEFAULT (getdate()),
  [OtherValues] [int] 
)

所有INSERT都使用IDENTITY和DateTime列的默认值执行,如下所示:

INSERT INTO [MyTable] ([OtherValues]) VALUES (1)

始终作为任何显式交易之外的独立报表。

我希望Id会严格增加,而InsertTime也会增加但不严格。但是在负载很重的情况下,我们会看到一些这样的情况:

| Id   | InsertTime              |
|------|-------------------------|
| 3740 | 2015-03-05 10:07:25.560 | 
| 3741 | 2015-03-05 10:07:25.557 |
| 3742 | 2015-03-05 10:07:25.577 |

我们在InsertTime中略有下降。

有谁知道这是怎么发生的,"右边"行的顺序?

4 个答案:

答案 0 :(得分:0)

标识列和DateTime列都可能存在问题,可能会导致意外结果,但是,我建议使用标识值而不是DateTime值来确定插入顺序。

虽然DateTime理论上应该随着时间的推移而增加,但由于从系统中检索当前时间的方式,可能缺乏精确度。对于所有细节,here's a link that explains a little of what is going on

使用标识列,通常预期它至少会提升,即使不是连续的。但是,请注意,如果更改种子,更改增量,重新启动服务器等,标识列也可能导致意外结果.Microsoft提供了身份值{{3}的保证列表}。

要记住的另一件事是,如果您正在使用事务,则该事务可以生成并获取标识,然后后续事务可以获取下一个标识值,理论上可以在更新之前提交其更改第一笔交易。

答案 1 :(得分:0)

记录的正确顺序是Identity列所描述的顺序 您描述的偏差完全在DateTime数据类型的可接受范围内(0.00333 ms)。

问题在于 Datetime数据类型并不准确。如果你的sql server版本支持它(即2008或更高版本),你应该使用Datetime2

  

日期时间值四舍五入为.000,.003或.007秒的增量,如下表所示。

在MSDN中查看日期和时间数据类型之间的comparison table

Read this article获得全面解释。

答案 2 :(得分:0)

行的“正确”顺序是标识列的顺序。虽然标识列的主要目的是提供唯一密钥,但它保证是唯一的并且是升序的。 datetime列没有确定正确排序顺序的准确性。即使您更改为datetime2列,也不要求时间始终为升序或唯一。

从某种角度来看,它们也是“正确的”。标识列正确表示标识值的确定顺序,日期时间列正确表示读取当前时间的时间。

由于数据库服务器正在执行大量多任务/多线程,因此无法保证整个事务将在另一个完整事务之前发生。由于在数据库内部为任务提供服务的方式,可能会启动一个事务,另一个事务启动并完成,然后完成第一个事务。

答案 3 :(得分:0)

人们希望标识列是正确的顺序,但是,它可能归结为数据的插入方式。例如,如果您在DatTable中有数据,并且正在将SQLBulkCopy执行到具有标识列的表并为数据库引擎配置以创建标识值,则它们不一定与DataTable数据的顺序相同。显然,SQLBulkCopy操作重新排序数据是一种看起来不错的方式,但它与DataTable中的行顺序不匹配。

在这种情况下,如果您想知道真正的插入顺序,您需要让应用程序而不是数据库设置您的身份/订单字段的值。要么使用BulkCopy,要么不使用BulkCopy。