【发布时间】:2021-07-06 16:16:37
【问题描述】:
我正在尝试根据数据库服务器的时钟生成一个唯一的 ID/时间戳。这不是表的主要 ID,但我感兴趣的是,该值对于每一行都是唯一的。此代码在一个存储过程中,将由同时运行的各个进程同时执行。
我想出了这段代码,但找不到让它更优雅的方法。据我测试,确保其他进程不会在其他线程上生成相同值的唯一方法是在检查存在时锁定表。
DECLARE @CurrentRRN varchar(30)
SET @CurrentRRN = FORMAT(SYSDATETIME(), 'yyyyMMddHHmmssffffff')
IF(EXISTS(SELECT RRN FROM dbo.Numbering WITH (xlock, tablockx, holdlock)
WHERE RRN = @CurrentRRN)) BEGIN
WHILE( EXISTS(SELECT RRN FROM dbo.Numbering WHERE RRN = @CurrentRRN) )
BEGIN
SET @CurrentRRN = FORMAT(SYSDATETIME(), 'yyyyMMddHHmmssffffff')
END
END
INSERT INTO dbo.Numbering
(RRN)
Values
(@CurrentRRN)
print @CurrentRRN
【问题讨论】:
-
应该是 datetime2 吗?也许你应该解释一下可能的目的是什么?
-
"...会同时执行..." 那样的话,怎么可能是唯一的呢?如果同时插入 2 条记录,则它不能是唯一的,除非您确实为整个过程锁定了表 - 这只会导致在最好的情况下缓慢插入,在最坏的情况下会导致死锁。如果你已经有一个主键,为什么还要让它唯一呢?
-
为什么不使用唯一标识符 (
NEWID())?这些将是独一无二的。如果您还想要一些日期时间(或日期时间2)值,只需添加一个额外的列。 -
原因是客户是从日期(他们的措辞 :P )生成的“数字字符串 id”,除了另一个表上使用的唯一 id (int)。因此,“编号”表用于生成和跟踪此 ID。这就是为什么我在生成它之后检查它是否存在,如果它已经由并行进程创建,则生成一个新的。每秒不会有数千条记录,但多个进程将访问此过程,我想确保没有重复。
-
首先考虑将
RRN更改为在“同一”时间插入的行的序列号,例如yyyyMMddHHmmssfffffff-nn。您可能需要考虑实现一个触发器,以便在为表执行insert时分配值。它将捕获SysDateTime,获取日期/时间的最大RRN值(如果有),增加序列号并更新表。请注意,如果insert涉及多行,则触发器将需要为行分配合适的、可能是顺序的值,可能按其他列排序。并处理溢出。
标签: sql sql-server tsql