J'ai une application qui crée des millions de tables dans une base de données SQL Server 2008 (non en cluster). Je cherche à mettre à niveau vers SQL Server 2014 (en cluster), mais je frappe un message d'erreur lorsqu'il est en charge:
"Il y a déjà un objet nommé 'PK__tablenameprefix__179E2ED8F259C33B' dans la base de données"
Il s'agit d'un nom de contrainte généré par le système. Il ressemble à un nombre 64 bits généré de manière aléatoire. Est-il possible que je constate des collisions en raison du grand nombre de tables? En supposant que j'ai 100 millions de tables, je calcule moins d'une chance de collision de 1 sur 1 trillion lors de l'ajout de la table suivante, mais cela suppose une distribution uniforme. Est-il possible que SQL Server ait changé son algorithme de génération de nom entre la version 2008 et 2014 pour augmenter les chances de collision?
L'autre différence significative est que mon instance de 2014 est une paire en cluster, mais j'ai du mal à formuler une hypothèse pour expliquer pourquoi cela générerait l'erreur ci-dessus.
PS Oui, je sais que créer des millions de tables est fou. Il s'agit d'un code tiers de boîte noire sur lequel je n'ai aucun contrôle. Malgré la folie, cela a fonctionné dans la version 2008 et maintenant pas dans la version 2014.
Edit: en y regardant de plus près, le suffixe généré semble toujours commencer par 179E2ED8 - ce qui signifie que la partie aléatoire n'est en fait qu'un nombre de 32 bits et que les chances de collision ne sont que de 1 sur 50 à chaque fois qu'une nouvelle table est ajoutée, ce qui correspond beaucoup plus au taux d'erreur que je constate!
Réponses:
Cela dépend du type de contrainte et de la version de SQL Server.
Exemple de résultats 2008
Exemple de résultats 2017
Pour les contraintes par défaut, les contraintes de vérification et les contraintes de clé étrangère, les 4 derniers octets du nom généré automatiquement sont une version hexadécimale de l'ID d'objet de la contrainte. Comme ils
objectid
sont garantis uniques, le nom doit également être unique. Dans Sybase aussi, ceux-ci utilisenttabname_colname_objectid
Pour les contraintes uniques et les contraintes de clé primaire utilisées par Sybase
Cela aussi garantirait l'unicité.
SQL Server n'utilise pas ce schéma.
Dans SQL Server 2008 et 2017, il utilise une chaîne de 8 octets à la fin du nom généré par le système, mais l'algorithme a changé la façon dont les 4 derniers octets sont générés.
En 2008, les 4 derniers octets représentent un compteur d'entier signé qui est décalé du
object_id
par-16000057
avec toute valeur négative enveloppant autour de max signé int. (L'importance de16000057
est qu'il s'agit de l'incrément appliqué entre les créations successivesobject_id
). Cela garantit toujours l'unicité.À partir de 2012, je ne vois aucun modèle entre l'id_objet de la contrainte et l'entier obtenu en traitant les 8 derniers caractères du nom comme la représentation hexadécimale d'un int signé.
Les noms de fonction dans la pile d'appels en 2017 montrent qu'il crée maintenant un GUID dans le cadre du processus de génération de nom (en 2008, je ne vois aucune mention
MDConstraintNameGenerator
). Je suppose que c'est pour fournir une source de hasard. De toute évidence, il n'utilise pas l'ensemble des 16 octets du GUID dans ces 4 octets qui changent entre les contraintes cependant.Je suppose que le nouvel algorithme a été fait pour une raison d'efficacité au détriment d'une possibilité accrue de collisions dans des cas extrêmes tels que le vôtre.
C'est tout à fait un cas pathologique car il nécessite que le préfixe du nom de table et le nom de colonne du PK (dans la mesure où cela affecte les 8 caractères précédant le 8 final) soient identiques pour des dizaines de milliers de tableaux avant qu'il ne devienne probable mais peut être reproduit assez facilement avec ci-dessous.
Un exemple exécuté sur SQL Server 2017 sur une base de données nouvellement créée a échoué en un peu plus d'une minute (après la création de 50 931 tables)
la source
N'oubliez pas que c'est le " problème d'anniversaire ". Vous n'essayez pas de générer une collision pour un hachage donné, mais plutôt de mesurer la probabilité qu'aucune des nombreuses paires de valeurs n'entre en collision.
Donc avec N tables, il y a N * (N-1) / 2 paires, donc ici environ 10 16 paires. Si la probabilité d'une collision est de 2 à 64 , la probabilité qu'une seule paire ne se heurte pas est de 1 à 2 -64 , mais avec autant de paires, la probabilité de ne pas avoir de collision ici est d'environ (1-2 à 64 ) 10 16 , ou plus comme 1/10 000. Voir par exemple https://preshing.com/20110504/hash-collision-probabilities/
Et s'il ne s'agit que d'un hachage 32 bits, la probabilité d'une collision passe de 1/2 à seulement 77k valeurs.
la source