Ich habe kürzlich eine SQL Server-Datenbank geerbt , die Guids speichert, BINARY(16)
anstatt sie UNIQUEIDENTIFIER
zu verwenden. Dies wird für alles ausgeführt, einschließlich der Primärschlüssel.
Sollte ich besorgt sein?
Ich habe kürzlich eine SQL Server-Datenbank geerbt , die Guids speichert, BINARY(16)
anstatt sie UNIQUEIDENTIFIER
zu verwenden. Dies wird für alles ausgeführt, einschließlich der Primärschlüssel.
Sollte ich besorgt sein?
Antworten:
Sollte ich besorgt sein?
Nun, es gibt ein paar Dinge, die ein wenig betreffen.
Erstens: Während es wahr ist, dass a UNIQUEIDENTIFIER
(dh Guid
) ein 16-Byte-Binärwert ist, ist es auch wahr, dass:
INT
können in gespeichert werden BINARY(4)
, DATETIME
können in BINARY(8)
usw. gespeichert werden), daher # 2 ↴sysname
als Alias für NVARCHAR(128)
).Die drei Verhaltensunterschiede, die ich finden kann, sind:
Das Vergleichen von UNIQUEIDENTIFIER
Werten in SQL Server zum Guten oder Schlechten erfolgt nicht auf die gleiche Weise wie das Vergleichen von BINARY(16)
Werten. Laut der MSDN-Seite zum Vergleichen von GUID- und Uniqueidentifier-Werten beim Vergleichen von UNIQUEIDENTIFIER
Werten in SQL Server:
Die letzten sechs Bytes eines Wertes sind am signifikantesten
Obwohl diese Werte nicht häufig sortiert werden, gibt es einen kleinen Unterschied zwischen diesen beiden Typen. Laut der MSDN-Seite für uniqueidentifier :
Die Reihenfolge wird nicht durch Vergleichen der Bitmuster der beiden Werte implementiert.
Da es Unterschiede in der Handhabung von GUID-Werten zwischen SQL Server und .NET gibt (siehe oben auf der Seite "Vergleichen von GUID- und Uniqueidentifier-Werten"), wird das Abrufen dieser Daten aus SQL Server in den Anwendungscode möglicherweise nicht ordnungsgemäß behandelt den App-Code, wenn das SQL Server-Vergleichsverhalten emuliert werden muss. Dieses Verhalten kann durch Konvertieren in a emuliert werden. Wüsste SqlGuid
ein Entwickler, dass dies möglich ist?
Zweitens: basierend auf der folgenden Aussage
Dies wird für alles ausgeführt, einschließlich der Primärschlüssel.
Ich würde im Allgemeinen für die Systemleistung besorgt sein, indem ich GUIDs als PKs anstelle von alternativen Schlüsseln zusammen mit einer INT
oder sogar BIGINT
als PK verwende. Und noch besorgter, wenn diese GUID-PKs die Clustered-Indizes sind.
Der folgende Kommentar des OP zur Antwort von @ Rob gibt Anlass zu zusätzlicher Besorgnis:
Es wurde von MySQL migriert
GUIDs können in 2 verschiedenen Binärformaten gespeichert werden . Es könnte also Anlass zur Sorge geben, abhängig von:
Das Problem, bei dem die Binärdarstellung generiert wurde, hat mit der Byte-Reihenfolge der ersten 3 der 4 "Felder" zu tun. Wenn Sie dem obigen Link zum Wikipedia-Artikel folgen, wird in RFC 4122 angegeben, dass für alle 4 Felder die Codierung "Big Endian" verwendet werden soll. Microsoft GUIDs geben jedoch "Native" Endianness an. Nun, die Intel-Architektur ist Little Endian, daher wird die Bytereihenfolge für die ersten drei Felder von Systemen umgekehrt, die dem RFC folgen (sowie von Microsoft-ähnlichen GUIDs, die auf Big Endian-Systemen generiert wurden). Das erste Feld "Daten 1" besteht aus 4 Bytes. In einer Endianness würde es als (hypothetisch) dargestellt werden 0x01020304
. Aber in der anderen Endianness wäre es 0x04030201
. Also, wenn die aktuelle Datenbank 'BINARY(16)
Diese binäre Darstellung wurde auf einem System nach dem RFC generiert. Die Konvertierung der aktuell im BINARY(16)
Feld vorhandenen Daten in eine UNIQUEIDENTIFIER
führt zu einer anderen GUID als ursprünglich erstellt. Dies ist kein wirkliches Problem, wenn die Werte die Datenbank nie verlassen haben und immer nur auf Gleichheit und Nicht-Reihenfolge verglichen werden.
Die Sorge bei der Bestellung ist einfach, dass sie nach der Konvertierung in nicht in derselben Reihenfolge sind UNIQUEIDENTIFIER
. Glücklicherweise wurde, wenn das ursprüngliche System wirklich MySQL war, die Bestellung nie in der Binärdarstellung ausgeführt, da MySQL nur eine Zeichenfolgendarstellung von UUID hat .
Das Problem mit den Zeichenfolgenwerten, die außerhalb der Datenbank verwendet werden, ist erneut schwerwiegender, wenn die Binärdarstellung außerhalb von Windows / SQL Server generiert wurde. Da die Bytereihenfolge möglicherweise unterschiedlich ist, würde dieselbe GUID in Zeichenfolgenform zu zwei verschiedenen Binärdarstellungen führen, je nachdem, wo diese Konvertierung stattgefunden hat. Wenn App-Code oder Kunden eine GUID in Zeichenfolgenform erhalten, ABC
die aus einer Binärform von stammt, 123
und die Binärdarstellung auf einem System nach dem RFC generiert wurde, wird dieselbe Binärdarstellung (dh 123
) DEF
bei der Konvertierung in eine Zeichenfolgenform von übersetzt a UNIQUEIDENTIFIER
. Ebenso würde die ursprüngliche Zeichenfolgenform von ABC
in eine binäre Form von 456
konvertiert, wenn sie in a konvertiert wird UNIQUEIDENTIFIER
.
Wenn die GUIDs die Datenbank also nie verlassen haben, gibt es außerhalb der Bestellung nicht viel zu befürchten. Oder wenn der Import von MySQL durch Konvertieren der Zeichenfolgenform (dh FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40
) durchgeführt wurde, ist dies möglicherweise in Ordnung. Wenn diese GUIDs an Kunden oder im App-Code vergeben wurden, können Sie testen, wie sie konvertieren, indem Sie eine abrufen und über konvertieren SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');
und prüfen, ob Sie den erwarteten Datensatz finden. Wenn Sie keine Datensätze finden können, müssen Sie die Felder möglicherweise so belassen BINARY(16)
.
Höchstwahrscheinlich wird es kein Problem geben, aber ich erwähne dies, weil es unter den richtigen Bedingungen ein Problem geben könnte.
Und wie werden neue GUIDs überhaupt eingefügt? Im App-Code generiert?
Wenn die vorherige Erläuterung des potenziellen Problems beim Importieren von GUID-Binärdarstellungen, die auf einem anderen System generiert wurden, ein wenig (oder viel) verwirrend war, wird hoffentlich Folgendes deutlicher:
DECLARE @GUID UNIQUEIDENTIFIER = NEWID();
SELECT @GUID AS [String], CONVERT(BINARY(16), @GUID) AS [Binary];
-- String = 5FED23BE-E52C-40EE-8F45-49664C9472FD
-- Binary = 0xBE23ED5F2CE5EE408F4549664C9472FD
-- BE23ED5F-2CE5-EE40-8F45-49664C9472FD
In der oben gezeigten Ausgabe stammen die Werte "String" und "Binary" von derselben GUID. Der Wert unter der Zeile "Binary" entspricht dem Wert der Zeile "Binary", ist jedoch im selben Stil wie die Zeile "String" formatiert (dh "0x" wurde entfernt und die vier Bindestriche hinzugefügt). Beim Vergleich des ersten und dritten Werts sind sie nicht genau gleich, aber sehr ähnlich: Die beiden Abschnitte ganz rechts sind identisch, die drei Abschnitte ganz links jedoch nicht. Wenn Sie jedoch genau hinschauen, können Sie feststellen, dass es sich in jedem der drei Abschnitte um dieselben Bytes handelt, nur in einer anderen Reihenfolge. Es ist möglicherweise einfacher zu erkennen, ob ich nur die ersten drei Abschnitte zeige und die Bytes nummeriere, damit leichter zu erkennen ist, wie sich ihre Reihenfolge zwischen den beiden Darstellungen unterscheidet:
Zeichenfolge = 1 5F 2 ED 3 23 4 BE - 5 E5 6 2C - 7 40 8 EE
Binär = 4 BE 3 23 2 ED 1 5F - 6 2C 5 E5 - 8 EE 7 40 (in Windows / SQL Server)
Innerhalb jeder Gruppierung ist die Reihenfolge der Bytes umgekehrt, jedoch nur innerhalb von Windows und auch von SQL Server. Auf einem System, das den RFC einhält, würde die Binärdarstellung jedoch die Sting-Darstellung spiegeln, da die Bytereihenfolge nicht umgekehrt würde.
Wie wurden die Daten von MySQL in SQL Server gebracht? Hier sind einige Möglichkeiten:
SELECT CONVERT(BINARY(16), '5FED23BE-E52C-40EE-8F45-49664C9472FD'),
CONVERT(BINARY(16), 0x5FED23BEE52C40EE8F4549664C9472FD),
CONVERT(BINARY(16), CONVERT(UNIQUEIDENTIFIER, '5FED23BE-E52C-40EE-8F45-49664C9472FD'));
Kehrt zurück:
0x35464544323342452D453532432D3430
0x5FED23BEE52C40EE8F4549664C9472FD
0xBE23ED5F2CE5EE408F4549664C9472FD
Unter der Annahme, dass es sich um eine direkte Binär-zu-Binär-Konvertierung handelt (dh obige Konvertierung Nr. 2), würde die resultierende GUID bei einer Konvertierung in eine tatsächliche wie UNIQUEIDENTIFIER
folgt lauten:
SELECT CONVERT(UNIQUEIDENTIFIER, 0x5FED23BEE52C40EE8F4549664C9472FD);
Kehrt zurück:
BE23ED5F-2CE5-EE40-8F45-49664C9472FD
Was falsch ist. Und das lässt uns drei Fragen offen:
Sie können immer besorgt sein. ;)
Das System wurde möglicherweise von einem anderen System migriert, das die eindeutige Kennung nicht unterstützt. Gibt es noch andere Kompromisse, die Sie nicht kennen?
Dem Designer ist der Typ der eindeutigen Kennung möglicherweise nicht bekannt. Welche anderen Dinge wussten sie nicht?
Technisch gesehen sollte es kein großes Problem sein.