我有一张表,用于在将信息发送到另一个系统(Dynamics CRM)之前对其进行排队。我将信息写入该队列,另一个服务出现并将数据写入CRM。
我使用了主键的标识值并将此密钥与信息一起保存,以便在出现任何问题时我可以跟踪它的来源。将数据拉出队列后,我删除了记录。
但是,看起来SQL Server正在重用身份字段上的密钥。许多ID只使用一次,但许多使用了两次,而且很多都使用了三次。显然,这使得查找历史的id无用。难道我做错了什么?我认为身份值应该是唯一的,表不应该重用它们。
如果有帮助,以下是该列的属性。
主键属性的更多属性:
答案 0 :(得分:2)
不确定您是如何检索身份的(@@ identity等),但是对于不同的方法存在一些与范围相关的限制。
以下是关于获取身份的3种方法的(有限但公平)的说明: http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
答案 1 :(得分:2)
IDENTITY本身并不意味着UNIQUE - 它只是意味着从当前种子值通过增量值自动递增。它是否已经存在这样的价值并不在乎。如果你还将列声明为唯一(在你的情况下,这通常意味着将其标记为主键),你将不会得到任何这些重复项,你应该很快发现谁是错误的,因为应用程序或用户将获得约束违规错误。
除了TRUNCATE TABLE之外,还有其他方法可以同样违反IDENTITY值:
DBCC CHECKIDENT()可用于手动将当前种子值设置为用户想要的任何内容。
SET IDENTITY_INSERT可用于手动覆盖下一个可用值。 Scribe可能会这样做,这样他们就不必关心你是否已经创建了一个标识值列,他们仍然可以用他们想要的任何方式覆盖它。
您可以运行服务器端跟踪来捕获这些事件,以确定是否有任何事件被调用。
指定您正在使用的SQL Server版本总是有用的,或者至少使用您需要支持的最低版本标记问题,例如,SQL Server 2000的解决方案和行为通常可能非常有用与SQL Server 2008 R2不同。对于未来的问题,这只是一个有用的提示。
答案 2 :(得分:2)
当需要时,身份值在表格中将是唯一的。
如果截断表,SQL引擎不知道旧的标识值。
如果您想要一个在表的生命周期内只使用过一次的值,您应该考虑GUID或根据identity + datetime创建一个唯一的密钥。
答案 3 :(得分:1)
TRUNCATE TABLE
语句将清除标识值。通过将IDENTITY_INSERT
设置为ON
,也可以专门插入身份值。
如果不了解系统的设计方式,我建议将该标识列作为主键(如果适用)或唯一索引。查看随后无法更新数据库的应用程序将显示新标识列的来源和位置。
但是,如上所述,如果您使用TRUNCATE TABLE
并且只是将这些标识列暴露在其他地方(例如在其他表中保留它们),则这是预期的行为。
如果要删除表中的所有行并希望不再重新标识该标识,则必须使用DELETE
命令。见MSDN
答案 4 :(得分:0)
如果您有相关的表格,我要做的第一件事就是确保您实际上已经设置了PK / FK关系。许多开发人员只是假设应用程序将处理此问题,并在发生类似情况时遇到麻烦。如果表有外键,则不能截断表,否则会阻止重用身份。
如果在同一个表中同时存在多个身份用途,则除非它是多个字段PK的一部分,否则该身份不能定义为PK。如果你确实有这种情况,我建议最好的办法是与微软协商,因为完全发生了一些严重的事情。如果人们正在拆除旧的并重新使用它们,那就是一个不同的故事。
显然有一些过程或人员因某种未知原因重置了过去的值。您可以使用DDL触发器来记录是否有人更改PK,删除外键约束等。至少这样您可以找到正在执行此操作的进程。