SQL Server插入数据时调用时间类ID生成函数出现重复值如何解决
解决方案
方案1:逐行插入加延迟(仅适合数据量小于100条的场景)
如果需要实现类似循环加sleep的逻辑,可以用游标逐行遍历Users表插入,每次插入后等待1毫秒,避免函数调用频率超过其精度阈值:
DECLARE @UserName VARCHAR(20), @UserAge VARCHAR(50) -- 声明游标遍历Users表数据 DECLARE user_cursor CURSOR FOR SELECT UserName, UserAge FROM USERS OPEN user_cursor FETCH NEXT FROM user_cursor INTO @UserName, @UserAge WHILE @@FETCH_STATUS = 0 BEGIN INSERT INTO Contacts (RecID,Name,Age) VALUES (dbo.GenerateRecID(), @UserName, @UserAge) -- 等待1毫秒,拉开函数调用间隔 WAITFOR DELAY '00:00:00.001' FETCH NEXT FROM user_cursor INTO @UserName, @UserAge END CLOSE user_cursor DEALLOCATE user_cursor
方案2:重试去重机制(比加延迟性能更稳定)
通过TRY CATCH捕获重复键错误,遇到冲突时自动重试生成ID,不需要强制等待,性能优于逐行加延迟方案:
DECLARE @UserName VARCHAR(20), @UserAge VARCHAR(50), @RecID VARCHAR(15), @RetryCount INT DECLARE user_cursor CURSOR FOR SELECT UserName, UserAge FROM USERS OPEN user_cursor FETCH NEXT FROM user_cursor INTO @UserName, @UserAge WHILE @@FETCH_STATUS = 0 BEGIN SET @RetryCount = 0 -- 最多重试3次避免死循环 WHILE @RetryCount < 3 BEGIN BEGIN TRY SET @RecID = dbo.GenerateRecID() INSERT INTO Contacts (RecID,Name,Age) VALUES (@RecID, @UserName, @UserAge) BREAK -- 插入成功跳出重试循环 END TRY BEGIN CATCH -- 判断是否为唯一约束/索引冲突错误 IF ERROR_NUMBER() IN (2601, 2627) BEGIN SET @RetryCount = @RetryCount + 1 WAITFOR DELAY '00:00:00.001' END ELSE BEGIN -- 非重复类错误直接抛出 THROW END END CATCH END FETCH NEXT FROM user_cursor INTO @UserName, @UserAge END CLOSE user_cursor DEALLOCATE user_cursor
方案3:无游标批量插入优化(性能最优,推荐优先尝试)
不需要游标逐行处理,通过ROW_NUMBER强制每行独立调用ID生成函数,避免批量查询时函数只被调用一次或者调用过快的问题:
INSERT INTO Contacts (RecID, Name, Age) SELECT fn.GenerateID, u.UserName, u.UserAge FROM ( -- 给每行分配唯一行号,强制每行做独立计算 SELECT UserName, UserAge, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNum FROM USERS ) u CROSS APPLY ( SELECT dbo.GenerateRecID() AS GenerateID ) fn
如果该方案仍有低概率重复,可以给Contacts表的RecID字段加上唯一约束,配合SQL Server的IGNORE_DUP_KEY索引选项使用,插入时自动忽略重复行后单独补插即可。
内容的提问来源于stack exchange,提问作者Pedro Emilio Vélez
相关产品推荐
相关产品推荐

