Gibt es eine Strafe für die Verwendung von BINARY (16) anstelle von UNIQUEIDENTIFIER?

19

Ich habe kürzlich eine SQL Server-Datenbank geerbt , die Guids speichert, BINARY(16)anstatt sie UNIQUEIDENTIFIERzu verwenden. Dies wird für alles ausgeführt, einschließlich der Primärschlüssel.

Sollte ich besorgt sein?

Jonathan Allen
quelle
Verwendet es durchgehend binary (16)? Einschließlich für Variablen und Parameter? Wenn nicht, müssen Sie die Auswirkungen impliziter Casts berücksichtigen.
Martin Smith
Ja, zum Glück muss ich mich auch nicht mit impliziten Casts befassen.
Jonathan Allen

Antworten:

21

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:

  1. Alle Daten können in binärer Form gespeichert werden (z. B. INTkönnen in gespeichert werden BINARY(4), DATETIMEkönnen in BINARY(8)usw. gespeichert werden), daher # 2 ↴
  2. Es gibt wahrscheinlich einen Grund für die Verwendung eines separaten Datentyps für GUIDs, der nicht nur der Zweckmäßigkeit dient (z. B. sysnameals Alias ​​für NVARCHAR(128)).

Die drei Verhaltensunterschiede, die ich finden kann, sind:

  • Das Vergleichen von UNIQUEIDENTIFIERWerten 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 UNIQUEIDENTIFIERWerten 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 SqlGuidein 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 INToder sogar BIGINTals PK verwende. Und noch besorgter, wenn diese GUID-PKs die Clustered-Indizes sind.

AKTUALISIEREN

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:

  1. auf welchem ​​System die Binärdarstellung generiert wurde, und
  2. Wenn die Zeichenfolgenwerte außerhalb des ursprünglichen Systems verwendet wurden, z. B. in App-Code oder an Clients zur Verwendung in Importdateien usw.

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 UNIQUEIDENTIFIERfü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, ABCdie 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) DEFbei der Konvertierung in eine Zeichenfolgenform von übersetzt a UNIQUEIDENTIFIER. Ebenso würde die ursprüngliche Zeichenfolgenform von ABCin eine binäre Form von 456konvertiert, 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?

UPDATE 2

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 UNIQUEIDENTIFIERfolgt lauten:

SELECT CONVERT(UNIQUEIDENTIFIER, 0x5FED23BEE52C40EE8F4549664C9472FD);

Kehrt zurück:

BE23ED5F-2CE5-EE40-8F45-49664C9472FD

Was falsch ist. Und das lässt uns drei Fragen offen:

  1. Wie wurden die Daten in SQL Server importiert?
  2. In welcher Sprache ist der App-Code geschrieben?
  3. Auf welcher Plattform läuft der App-Code?
Solomon Rutzky
quelle
Ich würde annehmen, dass die GUIDs in der Anwendung generiert werden, da ich sie nicht in der Datenbank sehe.
Jonathan Allen
Ich kann nicht sagen, dass ich der Erklärung zur Bytereihenfolge vollständig folge, aber ich muss über die Indizierung nachdenken. Wäre es mehr oder weniger wahrscheinlich, dass eine eindeutige Kennung zu einer Indexfragmentierung führt als eine binäre?
Jonathan Allen
2
@ JonathanAllen Ich habe einen weiteren UPDATE-Abschnitt hinzugefügt, um dies hoffentlich besser zu erklären. Und nein, die Indizierung sollte nicht anders sein.
Solomon Rutzky
"Gott sei Dank", SQL Server ändert die Reihenfolge zwischen Variante 1 und Variante 2 nicht - auch wenn "anders" auf der Festplatte gespeichert werden könnte, ist die Reihenfolge immer gleich verwirrend.
user2864740
5

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.

Rob Farley
quelle
Ja, es wurde von MySQL migriert. Und ja, es gibt viele interessante Dinge zu sehen.
Jonathan Allen