Sql server 有效生成唯一随机数
我们正在使用概述的技术生成无冲突的随机记录ID。简而言之,我们创建了一个包含每个可能ID的随机排序表,并在使用时将每个记录标记为“take” 我使用以下存储过程获取ID:Sql server 有效生成唯一随机数,sql-server,tsql,sql-server-2012,Sql Server,Tsql,Sql Server 2012,我们正在使用概述的技术生成无冲突的随机记录ID。简而言之,我们创建了一个包含每个可能ID的随机排序表,并在使用时将每个记录标记为“take” 我使用以下存储过程获取ID: ALTER PROCEDURE spc_GetId @retVal BIGINT OUTPUT AS DECLARE @curUpdate TABLE (Id BIGINT); SET NOCOUNT ON; UPDATE IdMasterList SET Taken=1 OUTPUT DELETED.
ALTER PROCEDURE spc_GetId @retVal BIGINT OUTPUT
AS
DECLARE @curUpdate TABLE (Id BIGINT);
SET NOCOUNT ON;
UPDATE IdMasterList SET Taken=1
OUTPUT DELETED.Id INTO @curUpdate
WHERE ID=(SELECT TOP 1 ID FROM IdMasterList WITH (INDEX(IX_Taken)) WHERE Taken IS NULL ORDER BY SeqNo);
SELECT TOP 1 @retVal=Id FROM @curUpdate;
RETURN;
ID的检索必须是一个原子操作,因为可以同时插入
对于大的插入(1000多万),这个过程相当慢,因为我必须通过游标遍历要插入的表
IdMasterList有一个架构:
SeqNo (BIGINT, NOT NULL) (PK) -- sequence of ordered numbers
Id (BIGINT) -- sequence of random numbers
Taken (BIT, NULL) -- 1 if taken, NULL if not
IX_索引为:
CREATE NONCLUSTERED INDEX (IX_Taken) ON IdMasterList (Taken ASC)
我通常以以下方式使用ID填充表:
DECLARE @recNo BIGINT;
DECLARE @newId BIGINT;
DECLARE newAdds CURSOR FOR SELECT recNo FROM Adds
OPEN newAdds;
FETCH NEXT FROM newAdds INTO @recNo;
WHILE @@FETCH_STATUS=0 BEGIN
EXEC spc_GetId @newId OUTPUT;
UPDATE Adds SET id=@newId WHERE recNo=@recNo;
FETCH NEXT FROM newAdds INTO @id;
END;
CLOSE newAdds;
DEALLOCATE newAdds;
问题:
在每个表上放置一个PK inden BigInt
insert into user (name)
values ().....
update user set = user.ID = id.ID
from id
left join usr
on usr.PK = id.PK
where user.ID = null;
一个
在每个表上放置一个PK inden BigInt
insert into user (name)
values ().....
update user set = user.ID = id.ID
from id
left join usr
on usr.PK = id.PK
where user.ID = null;
一个
在每个表上放置一个PK inden BigInt
insert into user (name)
values ().....
update user set = user.ID = id.ID
from id
left join usr
on usr.PK = id.PK
where user.ID = null;
一个
在每个表上放置一个PK inden BigInt
insert into user (name)
values ().....
update user set = user.ID = id.ID
from id
left join usr
on usr.PK = id.PK
where user.ID = null;
一个
与SQLServer中的大多数内容一样,如果您使用的是游标,那么您就错了 由于您使用的是SQL Server 2012,因此可以使用
序列
跟踪您已经使用的随机值,并有效地替换take
列
CREATE SEQUENCE SeqNoSequence
AS bigint
START WITH 1 -- Start with the first SeqNo that is not taken yet
CACHE 1000; -- Increase the cache size if you regularly need large blocks
用法:
CREATE TABLE #tmp
(
recNo bigint,
SeqNo bigint
)
INSERT INTO #tmp (recNo, SeqNo)
SELECT recNo,
NEXT VALUE FOR SeqNoSequence
FROM Adds
UPDATE Adds
SET id = m.id
FROM Adds a
INNER JOIN #tmp tmp ON a.recNo = tmp.recNo
INNER JOIN IdMasterList m ON tmp.SeqNo = m.SeqNo
序列是原子的。后续对SeqNoSequence的下一个值的调用保证返回唯一值,即使对于并行进程也是如此。请注意,SeqNo
中可能会有一些空白,但对于速度的大幅提升来说,这是一个非常小的折衷。与SQL Server中的大多数内容一样,如果您使用的是游标,那么您就错了
由于您使用的是SQL Server 2012,因此可以使用序列
跟踪您已经使用的随机值,并有效地替换take
列
CREATE SEQUENCE SeqNoSequence
AS bigint
START WITH 1 -- Start with the first SeqNo that is not taken yet
CACHE 1000; -- Increase the cache size if you regularly need large blocks
用法:
CREATE TABLE #tmp
(
recNo bigint,
SeqNo bigint
)
INSERT INTO #tmp (recNo, SeqNo)
SELECT recNo,
NEXT VALUE FOR SeqNoSequence
FROM Adds
UPDATE Adds
SET id = m.id
FROM Adds a
INNER JOIN #tmp tmp ON a.recNo = tmp.recNo
INNER JOIN IdMasterList m ON tmp.SeqNo = m.SeqNo
序列是原子的。后续对SeqNoSequence的下一个值的调用保证返回唯一值,即使对于并行进程也是如此。请注意,SeqNo
中可能会有一些空白,但对于速度的大幅提升来说,这是一个非常小的折衷。与SQL Server中的大多数内容一样,如果您使用的是游标,那么您就错了
由于您使用的是SQL Server 2012,因此可以使用序列
跟踪您已经使用的随机值,并有效地替换take
列
CREATE SEQUENCE SeqNoSequence
AS bigint
START WITH 1 -- Start with the first SeqNo that is not taken yet
CACHE 1000; -- Increase the cache size if you regularly need large blocks
用法:
CREATE TABLE #tmp
(
recNo bigint,
SeqNo bigint
)
INSERT INTO #tmp (recNo, SeqNo)
SELECT recNo,
NEXT VALUE FOR SeqNoSequence
FROM Adds
UPDATE Adds
SET id = m.id
FROM Adds a
INNER JOIN #tmp tmp ON a.recNo = tmp.recNo
INNER JOIN IdMasterList m ON tmp.SeqNo = m.SeqNo
序列是原子的。后续对SeqNoSequence的下一个值的调用保证返回唯一值,即使对于并行进程也是如此。请注意,SeqNo
中可能会有一些空白,但对于速度的大幅提升来说,这是一个非常小的折衷。与SQL Server中的大多数内容一样,如果您使用的是游标,那么您就错了
由于您使用的是SQL Server 2012,因此可以使用序列
跟踪您已经使用的随机值,并有效地替换take
列
CREATE SEQUENCE SeqNoSequence
AS bigint
START WITH 1 -- Start with the first SeqNo that is not taken yet
CACHE 1000; -- Increase the cache size if you regularly need large blocks
用法:
CREATE TABLE #tmp
(
recNo bigint,
SeqNo bigint
)
INSERT INTO #tmp (recNo, SeqNo)
SELECT recNo,
NEXT VALUE FOR SeqNoSequence
FROM Adds
UPDATE Adds
SET id = m.id
FROM Adds a
INNER JOIN #tmp tmp ON a.recNo = tmp.recNo
INNER JOIN IdMasterList m ON tmp.SeqNo = m.SeqNo
序列是原子的。后续对SeqNoSequence的下一个值的调用保证返回唯一值,即使对于并行进程也是如此。请注意,SeqNo
中可能存在差距,但对于速度的大幅提升来说,这只是一个很小的折衷。我想到的一些想法:
- 如果删除顶部、内部选择等有助于提高ID获取的性能,请尝试(查看统计io和查询计划):
- 将索引更改为过滤索引,因为我假设您不需要获取所获取的数字。如果我没记错的话,您不能对空值执行此操作,因此您需要将take更改为0/1
- 你到底有什么问题?获取单个ID还是1000多万个ID?CPU/I/O等问题是由游标和ID获取逻辑引起的,还是并行进程被其他进程阻塞
- 使用sequence对象获取SeqNo。然后使用idMasterList返回的值从idMasterList中获取Id。如果IdMasterList序列中没有空白,这可能会起作用
- 使用readpass提示可以帮助阻塞,对于CPU/I/O问题,您应该尝试优化SQL
- 如果原因纯粹是表是一个热点,而且似乎没有其他简单的解决方案可以提供帮助,请将其拆分为多个表,并使用某种简单的逻辑(甚至是@spid、rand()或类似的逻辑)来决定应从哪个表获取ID。如果所有表都有空闲的数字,您需要进行更多的检查,但情况应该不会那么糟
- 创建不同的过程(甚至表格)来处理单个ID、数百个ID和数百万个ID的获取
我脑子里有几个想法:
- 如果删除顶部、内部选择等有助于提高ID获取的性能,请尝试(查看统计io和查询计划):
- 将索引更改为过滤索引,因为我假设您不需要获取所获取的数字。如果我没记错的话,您不能对空值执行此操作,因此您需要将take更改为0/1
- 你到底有什么问题?获取单个ID还是1000多万个ID?CPU/I/O等问题是由游标和ID获取逻辑引起的,还是并行进程被其他进程阻塞
- 使用sequence对象获取SeqNo。然后使用idMasterList返回的值从idMasterList中获取Id。如果IdMasterList序列中没有空白,这可能会起作用
- 使用readpass提示可以帮助阻塞,对于CPU/I/O问题,您应该尝试优化SQL
- 如果原因纯粹是表格成为热点,而且似乎没有其他简单的解决方案可以提供帮助,那么拆分