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!
Respostas:
Isso depende do tipo de restrição e versão do SQL Server.
Resultados de exemplo 2008
Resultados de exemplo 2017
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
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 de16000057
é 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.
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)
fonte
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.
fonte