O SQL Server pode criar colisões nos nomes de restrições geradas pelo sistema?


14

Eu tenho um aplicativo que cria milhões de tabelas em um banco de dados do SQL Server 2008 (sem cluster). Estou procurando atualizar para o SQL Server 2014 (clusterizado), mas estou recebendo uma mensagem de erro quando está sob carga:

“Já existe um objeto chamado 'PK__tablenameprefix__179E2ED8F259C33B' no banco de dados”

Este é um nome de restrição gerado pelo sistema. Parece um número de 64 bits gerado aleatoriamente. É possível que eu esteja vendo colisões devido ao grande número de tabelas? Supondo que tenho 100 milhões de tabelas, calculo menos de uma chance de 1 em 1 trilhão de colisões ao adicionar a tabela a seguir, mas isso pressupõe uma distribuição uniforme. É possível que o SQL Server tenha alterado seu algoritmo de geração de nome entre as versões 2008 e 2014 para aumentar as chances de colisão?

A outra diferença significativa é que minha instância de 2014 é um par em cluster, mas estou lutando para formar uma hipótese de por que isso geraria o erro acima.

PS Sim, eu sei que criar milhões de tabelas é uma loucura. Este é um código de terceiros de caixa preta sobre o qual não tenho controle. Apesar da insanidade, funcionou na versão 2008 e agora não na versão 2014.

Edit: em uma inspeção mais detalhada, o sufixo gerado sempre parece começar com 179E2ED8 - o que significa que a parte aleatória é na verdade apenas um número de 32 bits e as chances de colisões são de apenas 1 em 50 a cada vez que uma nova tabela é adicionada, o que é uma correspondência muito mais próxima da taxa de erro que estou vendo!


Os nomes das tabelas são diferentes, mas eles usam uma convenção de nomenclatura que resulta em pelo menos os 11 primeiros caracteres iguais e isso parece ser tudo o que o SQL Server usa na geração do nome da restrição.
Jl6 26/04/19

O hardware subjacente é diferente (nova geração do DL380), mas não apresenta desempenho significativamente superior. O objetivo do exercício é substituir o SQL Server 2008 sem suporte, não melhorar a taxa de transferência e o hardware foi provisionado de acordo.
Jl6 26/04/19

Respostas:


15

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 objectidsã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_idby, -16000057com 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.

insira a descrição do link aqui

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.


11

Supondo que tenho 100 milhões de tabelas, calculo menos de uma chance de 1 em 1 trilhão de colisões

Lembre-se de que este é o " problema do aniversário ". Você não está tentando gerar uma colisão para um único hash, mas medindo a probabilidade de nenhum dos muitos pares de valores colidir.

Assim, com N tabelas, há N * (N-1) / 2 pares, então aqui estão cerca de 10 16 pares. Se a probabilidade de uma colisão é de 2 a 64 , a probabilidade de um único par não colidir é de 1-2 a 64 , mas com tantos pares, a probabilidade de não ter colisões aqui é de cerca de (1-2 a 64 ) 10 16 , ou mais como 1 / 10.000. Consulte, por exemplo, https://preshing.com/20110504/hash-collision-probabilities/

E se for apenas um hash de 32 bits, a probabilidade de uma colisão cruza 1/2 em apenas 77k valores.


2
E chegar aos valores de 77K em primeiro lugar sem encontrar uma colisão é provavelmente improvável, pois você precisa ter tido sorte com todas as criações anteriores antes disso. Eu me pergunto o que o ponto é onde a probabilidade cumulativa de uma colisão atinge 50%
Martin Smith
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.