Tengo una aplicación que crea millones de tablas en una base de datos de SQL Server 2008 (no agrupada). Estoy buscando actualizar a SQL Server 2014 (en clúster), pero aparece un mensaje de error cuando está bajo carga:
"Ya existe un objeto llamado 'PK__tablenameprefix__179E2ED8F259C33B' en la base de datos"
Este es un nombre de restricción generado por el sistema. Parece un número de 64 bits generado aleatoriamente. ¿Es posible que esté viendo colisiones debido a la gran cantidad de tablas? Suponiendo que tengo 100 millones de tablas, calculo menos de una probabilidad de 1 en 1 billón de colisión al agregar la siguiente tabla, pero eso supone una distribución uniforme. ¿Es posible que SQL Server haya cambiado su algoritmo de generación de nombres entre la versión 2008 y 2014 para aumentar las probabilidades de colisión?
La otra diferencia significativa es que mi instancia de 2014 es un par agrupado, pero estoy luchando por formar una hipótesis de por qué eso generaría el error anterior.
PD Sí, sé que crear millones de mesas es una locura. Este es un código de terceros de caja negra sobre el que no tengo control. A pesar de la locura, funcionó en la versión 2008 y ahora no en la versión 2014.
Editar: en una inspección más cercana, el sufijo generado siempre parece comenzar con 179E2ED8, lo que significa que la parte aleatoria en realidad es solo un número de 32 bits y las probabilidades de colisiones son solo 1 en 50 cada vez que se agrega una nueva tabla, que es una coincidencia mucho más cercana a la tasa de error que estoy viendo!
Respuestas:
Esto depende del tipo de restricción y la versión de SQL Server.
Resultados de ejemplo 2008
Resultados de ejemplo 2017
Para las restricciones predeterminadas, verifique las restricciones y las restricciones de clave externa, los últimos 4 bytes del nombre generado automáticamente son una versión hexadecimal del objectid de la restricción. Como
objectid
se garantiza único, el nombre también debe ser único. En Sybase también estos usantabname_colname_objectid
Para restricciones únicas y restricciones de clave principal, Sybase utiliza
Esto también garantizaría la singularidad.
SQL Server no usa este esquema.
Tanto en SQL Server 2008 como en 2017 utiliza una cadena de 8 bytes al final del nombre generado por el sistema, sin embargo, el algoritmo ha cambiado en cuanto a cómo se generan los últimos 4 bytes.
En 2008 los últimos 4 bytes representan un contador entero con signo que está desplazado del
object_id
por-16000057
con cualquier valor de ajuste de negativo en torno a int firmado máx. (La importancia de16000057
es que este es el incremento aplicado entre sucesivamente creadoobject_id
). Esto todavía garantiza la unicidad.En 2012 hacia arriba, no veo ningún patrón entre el object_id de la restricción y el entero obtenido al tratar los últimos 8 caracteres del nombre como la representación hexadecimal de un int con signo.
Los nombres de las funciones en la pila de llamadas en 2017 muestran que ahora crea un GUID como parte del proceso de generación de nombres (en 2008 no veo mención de
MDConstraintNameGenerator
). Supongo que esto es para proporcionar alguna fuente de aleatoriedad. Claramente, no está usando los 16 bytes completos del GUID en esos 4 bytes que, sin embargo, cambian entre restricciones.Supongo que el nuevo algoritmo se realizó por alguna razón de eficiencia a expensas de una mayor posibilidad de colisiones en casos extremos como el suyo.
Este es un caso bastante patológico ya que requiere que el prefijo del nombre de la tabla y el nombre de la columna de la PK (en la medida en que esto afecte a los 8 caracteres que preceden a los 8 finales) sean idénticos para decenas de miles de tablas antes de que sea probable, pero puede reproducirse bastante fácilmente con el siguiente.
Un ejemplo ejecutado en SQL Server 2017 contra una base de datos recién creada falló en poco más de un minuto (después de haber creado 50,931 tablas)
fuente
Recuerde que este es el " problema del cumpleaños ". No está intentando generar una colisión para un solo hash dado, sino que está midiendo la probabilidad de que ninguno de los muchos pares de valores choque.
Entonces, con N tablas, hay N * (N-1) / 2 pares, así que aquí hay unos 10 16 pares. Si la probabilidad de una colisión es de 2 a 64 , la probabilidad de que un solo par no colisione es de 1-2 a 64 , pero con tantos pares, la probabilidad de no tener colisiones aquí es de aproximadamente (1-2 a 64 ) 10 16 , o más como 1 / 10,000. Ver, por ejemplo, https://preshing.com/20110504/hash-collision-probabilities/
Y si es solo un hash de 32 bits, la probabilidad de una colisión cruza 1/2 a solo 77k.
fuente