Ich habe eine Anwendung, die Millionen von Tabellen in einer SQL Server 2008-Datenbank erstellt (nicht gruppiert). Ich möchte ein Upgrade auf SQL Server 2014 (geclustert) durchführen, erhalte jedoch unter Last eine Fehlermeldung:
"In der Datenbank befindet sich bereits ein Objekt mit dem Namen" PK__tablenameprefix__179E2ED8F259C33B "."
Dies ist ein vom System generierter Einschränkungsname. Es sieht aus wie eine zufällig generierte 64-Bit-Zahl. Ist es möglich, dass ich aufgrund der großen Anzahl von Tabellen Kollisionen sehe? Angenommen, ich habe 100 Millionen Tabellen, dann berechne ich beim Hinzufügen der nächsten Tabelle weniger als eine 1-in-1-Billion-Wahrscheinlichkeit für eine Kollision, aber das setzt eine gleichmäßige Verteilung voraus. Ist es möglich, dass SQL Server seinen Algorithmus zur Namensgenerierung zwischen 2008 und 2014 geändert hat, um die Kollisionswahrscheinlichkeit zu erhöhen?
Der andere wichtige Unterschied ist, dass meine 2014-Instanz ein Clustered Pair ist, aber ich habe Mühe, eine Hypothese zu erstellen, warum dies den obigen Fehler verursachen würde.
PS Ja, ich weiß, dass das Erstellen von Millionen von Tabellen verrückt ist. Dies ist ein Blackbox-Code von Drittanbietern, über den ich keine Kontrolle habe. Trotz des Wahnsinns funktionierte es in Version 2008 und jetzt nicht in Version 2014.
Bearbeiten: Bei näherer Betrachtung scheint das generierte Suffix immer mit 179E2ED8 zu beginnen - was bedeutet, dass der zufällige Teil eigentlich nur eine 32-Bit-Zahl ist und die Wahrscheinlichkeit von Kollisionen bei jedem Hinzufügen einer neuen Tabelle nur 1 zu 50 beträgt ist eine viel engere Übereinstimmung mit der Fehlerrate, die ich sehe!
Antworten:
Dies hängt von der Art der Einschränkung und der Version von SQL Server ab.
Beispielergebnisse 2008
Beispielergebnisse 2017
Bei Standardeinschränkungen, Prüfeinschränkungen und Fremdschlüsseleinschränkungen sind die letzten 4 Bytes des automatisch generierten Namens eine hexadezimale Version der Objekt-ID der Einschränkung. Da
objectid
garantiert eindeutig ist, muss der Name auch eindeutig sein. Auch in Sybase verwenden diesetabname_colname_objectid
Für eindeutige Einschränkungen und Primärschlüsseleinschränkungen verwendet Sybase
Auch dies würde die Einzigartigkeit garantieren.
SQL Server verwendet dieses Schema nicht.
In SQL Server 2008 und 2017 wird am Ende des vom System generierten Namens eine 8-Byte-Zeichenfolge verwendet. Der Algorithmus hat sich jedoch dahingehend geändert, wie die letzten 4 Bytes davon generiert werden.
Im Jahr 2008 stellen die letzten 4 Bytes einen vorzeichenbehafteten Ganzzahlzähler dar, der gegenüber dem
object_id
von versetzten-16000057
Wert mit einem negativen Umbruch auf max. Vorzeichenbehafteten Int. (Die Bedeutung von16000057
ist, dass dies das Inkrementobject_id
ist, das zwischen dem sukzessiven Erstellen angewendet wird .) Dies garantiert immer noch die Einzigartigkeit.Ab 2012 sehe ich überhaupt kein Muster zwischen der object_id der Einschränkung und der Ganzzahl, die erhalten wird, indem die letzten 8 Zeichen des Namens als hexadezimale Darstellung eines vorzeichenbehafteten int behandelt werden.
Die Funktionsnamen in der Aufrufliste im Jahr 2017 zeigen, dass es jetzt eine GUID als Teil des Namensgenerierungsprozesses erstellt (auf 2008 sehe ich keine Erwähnung von
MDConstraintNameGenerator
). Ich vermute, das ist eine Quelle der Zufälligkeit. Offensichtlich werden nicht die gesamten 16 Bytes der GUID in den 4 Bytes verwendet, die sich jedoch zwischen den Einschränkungen ändern.Ich gehe davon aus, dass der neue Algorithmus aus Effizienzgründen auf Kosten einer erhöhten Wahrscheinlichkeit von Kollisionen in extremen Fällen wie Ihrem durchgeführt wurde.
Dies ist ein pathologischer Fall, da das Präfix des Tabellennamens und der Spaltenname des PK (sofern dies die 8 Zeichen vor den letzten 8 beeinflusst) für Zehntausende von Tabellen identisch sein müssen, bevor dies wahrscheinlich wird, aber durchaus reproduzierbar ist leicht mit dem unten.
Ein Beispiel, das unter SQL Server 2017 für eine neu erstellte Datenbank ausgeführt wurde, schlug in etwas mehr als einer Minute fehl (nachdem 50.931 Tabellen erstellt wurden).
quelle
Denken Sie daran, dies ist das " Geburtstagsproblem ". Sie versuchen nicht, eine Kollision für einen einzelnen Hash zu generieren, sondern messen die Wahrscheinlichkeit, dass keines der vielen Wertepaare kollidiert.
Bei N Tabellen gibt es also N * (N-1) / 2 Paare, also hier ungefähr 10 16 Paare. Wenn die Wahrscheinlichkeit einer Kollision 2 bis 64 beträgt , beträgt die Wahrscheinlichkeit, dass ein einzelnes Paar nicht kollidiert, 1-2 bis 64 , aber bei so vielen Paaren beträgt die Wahrscheinlichkeit, dass hier keine Kollisionen auftreten, ungefähr (1-2 bis 64 ) 10 16 oder mehr wie 1 / 10.000. Siehe zB https://preshing.com/20110504/hash-collision-probabilities/
Und wenn es sich nur um einen 32-Bit-Hash handelt, überschreitet die Wahrscheinlichkeit einer Kollision die Hälfte bei nur 77.000 Werten.
quelle