O SQL Server pode criar colisões nos nomes de restrições geradas pelo sistema?
Isso depende do tipo de restrição e versão do SQL Server.
CREATE TABLE T1
(
A INT PRIMARY KEY CHECK (A > 0),
B INT DEFAULT -1 REFERENCES T1,
C INT UNIQUE,
CHECK (C > A)
)
SELECT name,
object_id,
CAST(object_id AS binary(4)) as object_id_hex,
CAST(CASE WHEN object_id >= 16000057 THEN object_id -16000057 ELSE object_id +2131483591 END AS BINARY(4)) AS object_id_offset_hex
FROM sys.objects
WHERE parent_object_id = OBJECT_ID('T1')
ORDER BY name;
drop table T1
Resultados de exemplo 2008
+--------------------------+-----------+---------------+----------------------+
| name | object_id | object_id_hex | object_id_offset_hex |
+--------------------------+-----------+---------------+----------------------+
| CK__T1__1D498357 | 491357015 | 0x1D498357 | 0x1C555F1E |
| CK__T1__A__1A6D16AC | 443356844 | 0x1A6D16AC | 0x1978F273 |
| DF__T1__B__1B613AE5 | 459356901 | 0x1B613AE5 | 0x1A6D16AC |
| FK__T1__B__1C555F1E | 475356958 | 0x1C555F1E | 0x1B613AE5 |
| PK__T1__3BD019AE15A8618F | 379356616 | 0x169C85C8 | 0x15A8618F |
| UQ__T1__3BD019A91884CE3A | 427356787 | 0x1978F273 | 0x1884CE3A |
+--------------------------+-----------+---------------+----------------------+
Resultados de exemplo 2017
+--------------------------+------------+---------------+----------------------+
| name | object_id | object_id_hex | object_id_offset_hex |
+--------------------------+------------+---------------+----------------------+
| CK__T1__59FA5E80 | 1509580416 | 0x59FA5E80 | 0x59063A47 |
| CK__T1__A__571DF1D5 | 1461580245 | 0x571DF1D5 | 0x5629CD9C |
| DF__T1__B__5812160E | 1477580302 | 0x5812160E | 0x571DF1D5 |
| FK__T1__B__59063A47 | 1493580359 | 0x59063A47 | 0x5812160E |
| PK__T1__3BD019AE0A4A6932 | 1429580131 | 0x5535A963 | 0x5441852A |
| UQ__T1__3BD019A981F522E0 | 1445580188 | 0x5629CD9C | 0x5535A963 |
+--------------------------+------------+---------------+----------------------+
Para restrições padrão, verifique restrições e restrições de chave estrangeira. Os últimos 4 bytes do nome gerado automaticamente são uma versão hexadecimal do ID do objeto da restrição. Como objectid
são garantidos exclusivos, o nome também deve ser exclusivo. No Sybase também essestabname_colname_objectid
Para restrições exclusivas e restrições de chave primária, a Sybase usa
tabname_colname_tabindid, em que tabindid é uma concatenação de seqüência de caracteres do ID da tabela e do índice
Isso também garantiria exclusividade.
O SQL Server não usa esse esquema.
No SQL Server 2008 e 2017, ele usa uma sequência de 8 bytes no final do nome gerado pelo sistema, no entanto, o algoritmo mudou na forma como os últimos 4 bytes disso são gerados.
Em 2008, os últimos 4 bytes representam um contador inteiro assinado que é compensado com object_id
by, -16000057
com qualquer valor negativo envolvendo o máximo de int assinado. (O significado de 16000057
é que este é o incremento aplicado entre criados sucessivamenteobject_id
). Isso ainda garante exclusividade.
Em 2012 em diante, não vejo nenhum padrão entre o object_id da restrição e o número inteiro obtido ao tratar os últimos 8 caracteres do nome como a representação hexadecimal de um int assinado.
Os nomes das funções na pilha de chamadas em 2017 mostram que agora ele cria um GUID como parte do processo de geração de nomes (em 2008 não vejo menção MDConstraintNameGenerator
). Eu acho que isso é para fornecer alguma fonte de aleatoriedade. Claramente, ele não está usando os 16 bytes inteiros do GUID nesses 4 bytes que mudam entre restrições no entanto.
Presumo que o novo algoritmo tenha sido realizado por algum motivo de eficiência, às custas de uma maior possibilidade de colisões em casos extremos como o seu.
Esse é um caso bastante patológico, pois exige que o prefixo do nome da tabela e o nome da coluna da PK (na medida em que isso afeta os 8 caracteres anteriores aos 8 finais) sejam idênticos para dezenas de milhares de tabelas antes que se torne provável, mas possam ser reproduzidos bastante. facilmente com o abaixo.
CREATE OR ALTER PROC #P
AS
SET NOCOUNT ON;
DECLARE @I INT = 0;
WHILE 1 = 1
BEGIN
EXEC ('CREATE TABLE abcdefghijklmnopqrstuvwxyz' + @I + '(C INT PRIMARY KEY)');
SET @I +=1;
END
GO
EXEC #P
Um exemplo de execução no SQL Server 2017 em um banco de dados recém-criado falhou em pouco mais de um minuto (após a criação de 50.931 tabelas)
Msg 2714, Nível 16, Estado 30, Linha 15 Já existe um objeto chamado 'PK__abcdefgh__3BD019A8175067CE' no banco de dados. Msg 1750, Nível 16, Estado 1, Linha 15 Não foi possível criar restrição ou índice. Veja erros anteriores.