checksum(newid()) 作为主键 - 如果发生冲突会发生什么?

us2*_*012 4 sql-server-2008 sql-server primary-key unique-constraint

检查我系统上某些软件使用的相当关键的数据库,我发现其中一个表在列上有一个主键Id,其中Id使用checksum(newid()). 这让我感到不安;在newids的保证是独一无二的,但通过将校验和(一个32位整数,大概是出于性能的原因?),你有一些机会,你在表中得到的碰撞(用1M行,我把那大约 1:4000 的机会,对我来说太多了)。

所以:

  • 我是否遗漏了一些关键的信息,表明上述内容实际上没问题?
  • 如果不是 - 如果应用程序尝试向表中插入新行并checksum(newid())给出一个已经存在的主键,会发生什么?我的桌子会炸吗?插入是否会失败并将其留给应用程序如何处理?

Aar*_*and 5

我必须假设应用程序的编写方式是尝试插入,如果失败,它只会再试一次。否则插入将失败(PK 违规)并且您的用户将抱怨并提交错误。

如果这样做的目的只是以随机顺序分配唯一编号,那么应用程序可能工作正常。我认为你应该只提交错误报告,如果你能证明应用程序在发生碰撞时做错了 - 考虑到可能的故障率并不容易。如果您有源代码访问权限,一个更简单的方法是查看他们执行插入的代码部分(或找出它是否调用存储过程来执行此操作)。

请记住,有一种更简单且容错的方法可以做到这一点。在前面建一张桌子,随机排列大量数字,然后在需要时从顶部拔出一个数字。

CREATE TABLE dbo.Destination(ID INT /*, other columns */);

CREATE TABLE dbo.Source
(
  RowNum INT PRIMARY KEY,
  ID INT, -- UNIQUE
  Used BIT NOT NULL DEFAULT 0
);

INSERT dbo.Source(RowNum, ID) 
SELECT ROW_NUMBER() OVER (ORDER BY NEWID()), ID
  FROM 
  (
    SELECT ID = CHECKSUM(NEWID()) 
      FROM sys.all_objects AS s1
      CROSS JOIN sys.all_objects AS s2
      -- should produce about 4 million rows,
      -- on my crappy VM this took two minutes,
      -- add another cross join if you need more
  )
  AS x GROUP BY ID; 
Run Code Online (Sandbox Code Playgroud)

然后当你需要添加一行时,你可以说:

UPDATE TOP (1) dbo.Source SET Used = 1
  OUTPUT inserted.ID /*, @params */ 
  INTO dbo.Destination
WHERE Used = 0;
Run Code Online (Sandbox Code Playgroud)

DELETE TOP (1)不过,您也可以让它们对审计等有用。)