DateTime.Now.Ticks在循环内重复

我正在尝试为表的主键生成一个唯一的ID,我正在使用DateTime.Now.Ticks 。 这是现在我们不能使用Identity

但有时,在循环内它会在连续迭代中生成相同的ID。 我的简化代码看起来像这样

  While(IncomingData.Next()) { IncomingData.ID = DateTime.Now.Ticks; // Other Operations . . . InsertInDatabase(IncomingData); } 

是因为我的处理器指令/秒的速度大于测量Ticks的精度吗? 我正在使用I5 2.9GHZ处理器。 虽然我通过引入计数变量并将其添加到ticks来解决了我的问题。 它不是一个好方法。 无论如何,有人可以为我分解它,因为如何计算tick是否取决于cpu周期? 谢谢。

我在您的策略中看到一些优点的唯一情况是,您需要在特定日期之间查询数据库中的数据。 否则,一个简单的整数计数器 – 从0或1开始 – 可能总是更好。

如果正确实施并按照使用方式使用,那么您的想法并不完全糟糕。 它可能只是不必要地复杂化。

我假设你希望你的主键是一个增加的整数,这是一个合理的要求,以保持您的插入快速与一些数据库。 GUID不适合您 。 我假设您不能使用自动递增的数据库密钥。 我还假设您不会从多个应用程序 – 也不是多台计算机 – 写入您的数据库。

首先,您需要考虑夏令时:使用DateTime.UtcNow而不是DateTime.Now。 这是因为DateTime.Now可以在夏令时的情况下向后跳。

其次,在极少数情况下 – 当系统时钟被调整时,你应该期望DateTime.UtcNow无论如何都要向后跳。 这意味着您无论如何都需要保存以前分配的值。

第三,正如您所知,系统时钟的精度不是无限的 – 通常是15毫秒 – 因此您需要保存先前分配的值并在DateTime.UtcNow返回相同值两次的情况下递增它。

第四,知道你需要保持一个保持先前分配值的变量,为什么不放弃整个DateTime的想法而只依赖于那个变量呢? 我的意思是:在程序开始时,您可以从数据库中读取最大值,将其存储到内存中的计数器中,然后在每次需要新键值时递增计数器。

使用DateTime.Now.Ticks作为数据库身份是一个非常糟糕的主意。 即使您解决了问题中的“重复问题”,您的应用程序将来可能会中断,例如,一个非常常见的情况,应用程序部署在多个服务器上。

您可以(1)使用数据库自​​动生成,自动增加ID,或(2)使用Guid来解决问题。

编辑在数据库性能考虑下,自动增加long ID在大多数情况下比guid具有更好的性能。

编辑tick作为时间测量单位处理,就像年/月/日/小时/分钟/秒/毫秒/纳秒一样。 Tick在毫秒和纳秒之间,1毫秒= 100000个刻度。

TL; DR:

DateTime.Now的精度约为15ms,如果循环速度快于此, DateTime.Now将在不同迭代次数上具有相同的值。


如.Net源代码中所述 :

数据存储为无符号64位整数

位01-62:100纳秒的值,其中0代表1/1/0001 12:00 am,直到值12/31/9999 23:59:59.9999999

此外, DateTime.Now非常不精确:

此属性的分辨率取决于系统计时器,在Windows系统上约为15毫秒


对于ID分配部分,如其他所述,使用为此目的而制作的GUID

据我所知,DateTime.Now.Ticks值在大多数当前计算机上大约每15ms更新一次,即使我已经读过它可以每1ms更新一次。 无论如何,它是一个需要由OS更新而不是直接从时钟读取的值,因此可以预期在两个不同的读取中获得相同的结果。 我建议您使用不同的,作为数据库或GUID上的自动增加值。

这篇文章阐述了这个问题: http : //www.nullskull.com/articles/20021111.asp

更好的方法是使用自动生成的Id

但是如果你想坚持使用DataTime Tick选项,那么你可以使用这种方法,根据你的时间给你一个唯一的数字。

 Random rand = new Random(DateTime.Now.Millisecond); 

此外,你可以使用

 Guid guid = Guid.NewGuid(); 

这也会给你一个唯一的号码。

谢谢!