给定一个SQL Server数据库表Organisation
包含smallint
列iCompanyID
(忽略命名约定,它的历史可以追溯到12年)既不是身份也不是索引,但必须是独特;查找表中尚不存在的新值的最快方法是什么?
问题在于我希望这可以保持快速,因为可能值的范围已用完。实际上我不希望使用超过几百个值,所以我的方法中的任何一个都能表现得很好,所以我不会问纯粹的兴趣。
我有两种方法,一种生成一个随机数,然后检查它是否存在于表中;如果不是它尝试另一个。这个方法可能永远不会完成,因为值已用完,所以不是一个好的答案。
DECLARE @companyId SMALLINT
DECLARE @value INT
WHILE @companyId IS NULL OR EXISTS (SELECT 1 FROM dbo.Organisation WHERE iCompanyID = @companyId)
BEGIN
SET @value = FLOOR(65535 * RAND(DATEPART(mm, GETDATE()) * 100000 + DATEPART(ss, GETDATE()) * 1000 + DATEPART(ms, GETDATE())) + 1)
IF @value > 32767
SET @companyId = @value - 65536
ELSE
SET @companyId = @value
END
SELECT @companyId [Available ID]
另一种方法基于this answer,并生成所有可能值的列表。这是外连接到表,并返回表中为空匹配的第一个可能值。测试表明,当值用完时,这也变得非常慢,但如果有一个可用值,它至少应该完成。
WITH q AS
(
SELECT firstId, lastId FROM (SELECT -32768 firstId, 32767 lastId) r
UNION ALL
SELECT firstId + 1, lastId FROM q WHERE firstId < lastId
)
SELECT TOP 1 q.firstId [Available ID]
FROM q LEFT JOIN dbo.Organisation o ON q.firstId = o.iCompanyID
WHERE o.iCompanyID IS NULL
OPTION (MAXRECURSION 0)
我确信比我自己更聪明的人可以找到一种方法来做到这一点,因为可用值减少并且我有兴趣看到其他可能的方法。
请不要在表格中添加索引;在我感兴趣的当前限制范围内的方法。
答案 0 :(得分:0)
更简单的方法是使用ROW_NUMBER
来查找未使用的第一个索引,但我不知道它是否比您的方法更快。最终,与其他方法一样,它仍然需要对数据进行排序并对其进行迭代,因此除非您能够对这些数据进行索引或非规范化,否则我无法看到大量的性能提升。
SELECT TOP 1 newId FROM
(
SELECT newId=(ROW_NUMBER() OVER (ORDER BY iCompanyId)) - 1, iCompanyId FROM Organisation
GROUP BY iCompanyId
) rownums
WHERE newId <> iCompanyId