我有一个表,其中包含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中略有下降。
有谁知道这是怎么发生的,"右边"行的顺序?
答案 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。