Как одновременно генерировать уникальные имена пользователей в общей базе данных?

Мне нужно автоматически генерировать имена учетных записей. Они будут использоваться в пользовательском программном обеспечении, которое будет обращаться к моему сервису, поэтому они не обязательно выглядят красиво. Думаю, подойдет любая достаточно длинная буквенно-цифровая строка. Предположим, у меня уже есть алгоритм, который создает достаточно хорошую буквенно-цифровую строку.

Есть два основных требования: они должны быть уникальными и генерироваться одновременно. В частности, моя служба будет работать на нескольких машинах, и все копии будут иметь доступ к одной и той же общей базе данных. Мне нужно сгенерировать эти имена пользователей таким образом, чтобы никакие два узла никогда не генерировали одинаковые имена пользователей.

Как мне это сделать? Мне просто оставить эту идею и использовать GUID? Есть ли более красивый способ, чем GUID для этого сценария?


person sharptooth    schedule 26.09.2011    source источник
comment
@Богдан Салеан: SQL Server 2008.   -  person sharptooth    schedule 26.09.2011


Ответы (2)


Один из:

  • Используйте идентификаторы GUID (тип данных уникального идентификатора), но не в качестве кластерного индекса.
  • Используйте столбец IDENTITY

Если репликация SQL Server используется на нескольких узлах (Правка: слишком много думал раньше)

  • Используйте столбцы IDENTITY с диапазонами, установленными для каждого узла (например, от -1 до -1000000, от 1 до 100000 и т. д.).
  • Столбец IDENTITY и столбец NodeID для разделения значений IDENTITY.

Все безопасны для параллелизма

person gbn    schedule 26.09.2011
comment
@sharptooth: ах! если вы имеете в виду клиентские узлы, то да, БД будет. Я думал о нескольких узлах в репликации SQL Server. - person gbn; 26.09.2011

CREATE TABLE dbo.CommonName
(
    CommonNameID INT IDENTITY(0,1) PRIMARY KEY
    ,Name NVARCHAR(50) NOT NULL
    ,LastID INT NOT NULL DEFAULT 0
);
INSERT  dbo.CommonName(Name)
VALUES  
 ('JAMES')  
,('JOHN')   
,('ROBERT') 
,('MICHAEL')    
,('WILLIAM')    
,('DAVID')  
,('RICHARD')    
,('CHARLES')    
,('JOSEPH') 
,('THOMAS');
GO

--Test
CREATE TABLE [User](Id INT IDENTITY(1,1) PRIMARY KEY, UserName NVARCHAR(60));
GO

UPDATE  dbo.CommonName WITH(ROWLOCK)
SET     
        LastID = LastID + 1
OUTPUT  inserted.Name+CAST(inserted.LastID AS NVARCHAR(10)) INTO [User](UserName)
WHERE   CommonNameID = ABS(CHECKSUM(NEWID())) % 10
GO 20 --We need 20 new users

SELECT  *
FROM    [User] u
ORDER BY u.Id;
--End of test
GO

DROP TABLE dbo.CommonName;
DROP TABLE dbo.[User];

Пример вывода:

Batch execution completed 20 times.
Id          UserName
----------- ------------------------------------------------------------
1           RICHARD1
2           MICHAEL1
3           ROBERT1
4           WILLIAM1
5           ROBERT2
6           JAMES1
7           CHARLES1
8           RICHARD2
9           JOSEPH1
10          THOMAS1
11          ROBERT3
12          MICHAEL2
13          WILLIAM2
14          MICHAEL3
15          THOMAS2
16          THOMAS3
17          WILLIAM3
18          RICHARD3
19          JAMES2
20          RICHARD4

(20 row(s) affected)

Если вы хотите протестировать этот код на наличие проблем параллелизма, вы можете запустить UPDATE ...; GO 100000 и UPDATE ...; GO 100 в SSMS в двух отдельных окнах/запросах, а в конце вы можете запустить этот запрос SELECT UserName, COUNT(*) Num FROM dbo.[User] ORDER BY COUNT(*) DESC, чтобы посмотреть, сможете ли вы найти дубликаты.

person Bogdan Sahlean    schedule 26.09.2011