【问题标题】:Generating a unique primary key生成唯一的主键
【发布时间】:2014-06-19 19:21:06
【问题描述】:

我有一个 SQL Server 数据库,其中包含许多都连接的表,每个表都有一个主键。我有一个Dictionary,它跟踪每个表的主键字段。我的任务是每天从以属性为中心的 XML 文件中提取数据并将它们插入到主数据库中。每个 XML 文件都具有相同的架构。我通过使用XMLReader 并将数据导入DataSet 来做到这一点。

我不能使用AutoNumber 作为键。假设昨天的 XML 文件生成了一个类似于以下内容的DataTable,并将其导入到数据库中

-------------------------------------
| Key | Column1 | Column2 | Column3 |
|-----------------------------------|
|  0  | dsfsfsd | sdfsrer | sdfsfsf |
|-----------------------------------|
|  1  | dertert | qweqweq | xczxsdf |
|-----------------------------------|
|  2  | prwersd | xzcsdfw | qwefkgs |
-------------------------------------

如果今天的 XML 文件生成以下 DataTable

-------------------------------------
| Key | Column1 | Column2 | Column3 |
|-----------------------------------|
|  0  | sesdfsd | hjghjgh | edrgffb |
|-----------------------------------|
|  1  | wrwerwr | zxcxfsd | pijghjh |
|-----------------------------------|
|  2  | vcbcvbv | vbnvnbn | bnvfgnf |
-------------------------------------

然后当我使用SqlBulkCopy 将新数据导入数据库时​​,就会出现重复键。我对此的解决方案是使用DateTime.Now.Ticks 生成唯一密钥。从理论上讲,这应该始终创建一个唯一的密钥。

但是,由于某种原因,DateTime.Now.Ticks 并不是唯一的。例如,一行中的 5 条记录可能都具有键 635387859864435908,接下来的 7 条记录可能具有键 635387859864592164,即使我在不​​同时间生成该值。我想说问题的原因是我的脚本在更新时间之前多次调用DateTime.Now.Ticks

其他人能想出更好的方法来生成密钥吗?

【问题讨论】:

  • 您是否有理由不能只使用 GUID?
  • DateTime.Now.Ticks 并不是唯一的。正如您所发现的,处理器在 tick 中可以完成的工作量实际上相当多。
  • @ChrisHaas 我还没有听说过 GUID。我现在正在研究它们,看看这是否能解决问题
  • 查看Eric Lippert's关于 GUID 的三部分文章了解更多信息。
  • 只是一个警告,如果您使用 GUID 作为主键并将其作为聚集索引(这是默认设置),则可能会出现性能问题,具体取决于您拥有的记录数。当我有 GUID PK 时,我通常会选择不同的列或一组列进行聚类。

标签: c# sql sql-server xml


【解决方案1】:

出于性能原因,DateTime.Now 的值可能会被缓存一小段时间。我们做了类似的事情,我们使用了 2 个可能的选项:

  1. 保留您在所在服务器上使用过的号码列表,如果您可以确定该号码已被使用,则增加该号码
  2. 将字段转换为字符串,并在其末尾附加 GUID 或其他一些随机标识符。可以使用System.Guid.NewGuid().ToString(); 创建 GUID

显然,这些计划都不会使碰撞风险为零,但它们可以帮助降低它。

【讨论】:

    【解决方案2】:

    如果您有大量数据并且需要为每一行设置一个唯一键,只需使用GUID

    【讨论】:

      【解决方案3】:

      您可以执行以下操作来获取唯一 ID (SQL Fiddle):

      SELECT
      CONCAT(YEAR(GETDATE()), DATEDIFF(DAY, STR(YEAR(GETDATE()), 4) + '0101',
      GETDATE() ) + 1,  ROW_NUMBER() OVER(ORDER BY id DESC)) UniqueID
      FROM supportContacts s
      

      如果您每天只运行一次查询,这将起作用。如果您每天运行不止一次,则需要获取秒数或其他内容 (SQL Fiddle):

      SELECT CONCAT(CurrYear, CurrJulian, CurrSeconds, Row) AS UniqueID
      FROM
      (
        SELECT
        YEAR(GETDATE()) AS CurrYear, 
        DATEDIFF(DAY, STR(YEAR(GETDATE()), 4) + '0101', GETDATE() ) + 1 AS CurrJulian,  
        ROW_NUMBER() OVER(ORDER BY id DESC) AS Row,
        datediff(second, left(convert(varchar(20), getdate(), 126), 10), getdate()) AS CurrSeconds
        from supportContacts s
      ) AS m
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-27
        • 2016-12-03
        • 2020-09-09
        • 1970-01-01
        • 1970-01-01
        • 2014-12-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多