70 Stimmen

Was sind die Leistungsverbesserungen von Sequential Guid gegenüber dem Standard Guid?

Hat jemand jemals die Leistung von Sequential Guid vs. Standard Guid gemessen, wenn sie als Primärschlüssel in einer Datenbank verwendet werden?


Ich sehe keine Notwendigkeit dafür, dass eindeutige Schlüssel erratbar oder nicht erratbar sein müssen. Sie von einer Web-Benutzeroberfläche oder an anderer Stelle zu übergeben, scheint an sich schon eine schlechte Praxis zu sein und ich sehe nicht, wie die Verwendung eines Guid die Dinge verbessern kann (wenn dies der Fall ist, verwenden Sie einen echten Zufallszahlengenerator mit den richtigen Kryptofunktionen des Frameworks).
Die anderen Punkte sind durch meinen Ansatz abgedeckt, ein Sequential Guid kann aus dem Code generiert werden, ohne auf die Datenbank zugreifen zu müssen (auch wenn dies nur für Windows gilt) und er ist eindeutig in Zeit und Raum.
Und ja, die Frage wurde gestellt, um sie zu beantworten, um denjenigen, die Guids für ihre PK gewählt haben, einen Weg zu geben, die Datenbanknutzung zu verbessern (in meinem Fall hat dies den Kunden ermöglicht, eine viel höhere Arbeitslast zu bewältigen, ohne die Server ändern zu müssen).

Es scheint, dass Sicherheitsbedenken eine Rolle spielen, in diesem Fall verwenden Sie keine Sequential Guid oder, noch besser, verwenden Sie Standard Guid für PKs, die von Ihrer Benutzeroberfläche hin und her übergeben werden, und Sequential Guid für alles andere. Wie immer gibt es keine absolute Wahrheit, ich habe auch die Hauptantwort bearbeitet, um dies widerzuspiegeln.

117voto

massimogentilini Punkte 4052

GUID vs.Sequential GUID

Ein typisches Muster ist die Verwendung von Guid als PK für Tabellen, aber wie in anderen Diskussionen erwähnt (siehe Vor- und Nachteile von GUID / UUID-Datenbankschlüsseln), gibt es einige Leistungsprobleme.

Dies ist eine typische Guid-Sequenz

f3818d69-2552-40b7-a403-01a6db4552f7
7ce31615-fafb-42c4-b317-40d21a6a3c60
94732fc7-768e-4cf2-9107-f0953f6795a5

Probleme dieser Art von Daten sind:<
-

  • Weite Verteilung von Werten
  • Fast zufällige
  • Indexnutzung ist sehr, sehr, sehr schlecht
  • Viele Leaf-Verschiebungen
  • Fast alle PK müssen zumindest in einem nicht gruppierten Index sein
  • Problem tritt sowohl bei Oracle als auch bei SQL Server auf

Eine mögliche Lösung ist die Verwendung von Sequential Guid, die wie folgt generiert werden:

cc6466f7-1066-11dd-acb6-005056c00008
cc6466f8-1066-11dd-acb6-005056c00008
cc6466f9-1066-11dd-acb6-005056c00008

Wie man sie aus C#-Code generiert:

[DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(out Guid guid);

public static Guid SequentialGuid()
{
    const int RPC_S_OK = 0;
    Guid g;
    if (UuidCreateSequential(out g) != RPC_S_OK)
        return Guid.NewGuid();
    else
        return g;
}

Vorteile

  • Bessere Indexnutzung
  • Erlauben die Verwendung von gruppierten Schlüsseln (in NLB-Szenarien zu überprüfen)
  • Weniger Festplattenauslastung
  • 20-25% Leistungssteigerung bei geringfügigen Kosten

Reale Messung: Szenario:

  • Guid gespeichert als UniqueIdentifier Datentypen auf SQL Server
  • Guid als CHAR(36) in Oracle gespeichert
  • Viele Einfügevorgänge, gruppiert in einer einzigen Transaktion
  • Von 1 bis zu 100 Einfügungen je nach Tabelle
  • Einige Tabellen > 10 Millionen Zeilen

Labor-Test - SQL Server

VS2008 Test, 10 gleichzeitige Benutzer, keine Wartezeit, Benchmark-Prozess mit 600 Einfügungen im Batch für Leaf-Tabelle
Standard Guid
Durchschnittliche Prozessdauer: 10,5 Sek.
Durchschnittliche Anfragen pro Sekunde: 54,6
Durchschnittliche Antwortzeit: 0,26

Sequential Guid
Durchschnittliche Prozessdauer: 4,6 Sek.
Durchschnittliche Anfragen pro Sekunde: 87,1
Durchschnittliche Antwortzeit: 0,12

Ergebnisse in Oracle (Entschuldigung, ein anderes Tool wurde für den Test verwendet) 1.327.613 Einfügungen in einer Tabelle mit einem Guid PK

Standard Guid, 0,02 Sek. vergangene Zeit für jede Einfügung, 2,861 Sek. CPU-Zeit, insgesamt 31,049 Sek. vergangen

Sequential Guid, 0,00 Sek. vergangene Zeit für jede Einfügung, 1,142 Sek. CPU-Zeit, insgesamt 3,667 Sek. vergangen

Die DB-Datei-Sequenzlese-Wartezeit ging von 6,4 Millionen Warteereignissen für 62,415 Sekunden auf 1,2 Millionen Warteereignisse für 11,063 Sekunden über.

Es ist wichtig zu sehen, dass alle sequenziellen Guid erraten werden können, daher ist es keine gute Idee, sie zu verwenden, wenn Sicherheit ein Anliegen ist, weiterhin Standard-Guid verwenden. Um es kurz zu machen...Wenn Sie Guid als PK verwenden, verwenden Sie sequenzielle Guid jedes Mal, wenn sie nicht hin und her von einer Benutzeroberfläche übergeben werden, sie beschleunigen Vorgänge und kosten nichts zu implementieren.

0 Stimmen

Mit dem Speicher-Engine 'InnoDB' speichert MySQL Datensätze nach PK auf eine gruppierte Weise, daher sollten Sie hier auch von Sequenziellen GUIDs profitieren.

1 Stimmen

"Es ist wichtig zu erkennen, dass alle aufeinanderfolgenden GUIDs geraten werden können, daher ist es keine gute Idee, sie zu verwenden, wenn Sicherheit ein Anliegen ist." In diesem Fall könnte stattdessen ein Comb-GUID verwendet werden, der den Vorteil hat, sowohl aufeinanderfolgend als auch zufällig zu sein.

1 Stimmen

Sehen Sie sich diesen Blog-Beitrag an: blogs.msdn.com/b/dbrowne/archive/2012/07/03/… "... die Ergebnisse von UuidCreateSequential sind nicht mit der SQL Server-Sortierreihenfolge sequenziell ... Um sie sequenziell zu machen, führt die interne NEWSEQUENTIALID-Funktion von SQL Server einige Byte-Verschiebungen am GUID durch ... Sie müssen dieselben Byte-Verschiebungen durchführen"

65voto

Dan Punkte 58216

Ich könnte hier etwas übersehen (korrigiere mich gerne, wenn ich falsch liege), aber ich sehe sehr wenig Nutzen darin, sequenzielle GUID/UUIDs für Primärschlüssel zu verwenden.

Der Zweck der Verwendung von GUIDs oder UUIDs anstelle von selbstinkrementierenden Ganzzahlen ist:

  • Sie können überall erstellt werden ohne die Datenbank zu kontaktieren
  • Sie sind Kennungen, die innerhalb Ihrer Anwendung vollständig einzigartig sind (und im Falle von UUIDs universell einzigartig)
  • Geht man von einer Kennung aus, gibt es keine Möglichkeit, die nächste oder vorherige (oder überhaupt irgendwelche anderen gültigen Kennungen) zu erraten, ohne einen riesigen Schlüsselraum zu durchbrute force'n.

Leider verlieren Sie bei Verwendung Ihres Vorschlags all diese Dinge.

Also ja. Sie haben GUIDs besser gemacht. Aber dabei haben Sie fast alle Gründe verworfen, sie überhaupt zu verwenden.

Wenn Sie die Leistung wirklich verbessern wollen, verwenden Sie einen standardmäßigen selbstinkrementierenden Ganzzahl-Primärschlüssel. Das bietet alle von Ihnen beschriebenen Vorteile (und mehr), während es in fast jeder Hinsicht besser ist als ein 'sequenzieller guid'.

Dies wird höchstwahrscheinlich ins Nirwana hinabgestimmt, da es Ihre Frage nicht direkt beantwortet (die offensichtlich sorgfältig formuliert wurde, damit Sie sie sofort selbst beantworten können), aber ich halte es für eine weit wichtigere Frage.

1 Stimmen

Neben dem "Nicht-Raten" (das ich nicht für wichtig halte, wir suchen nicht nach einer Zufallsfunktion) haben die sequentiellen GUID genau die Eigenschaft, nach der Sie suchen. Ich generiere sie aus C#-Code und sie sind eindeutig in Zeit und Raum.

17 Stimmen

Sequentielle UUIDs garantieren keine globale Reihenfolge. Sie sind immer noch eindeutig, aber auch lokal aufeinanderfolgend. Das bedeutet, dass IDs, die auf verschiedenen Hosts/Prozessen/Threads generiert werden (je nach sequentiellem Schema), zufällig miteinander verschachtelt sind, aber IDs, die in der gleichen Umgebung generiert werden, geordnet sein werden.

2 Stimmen

COMB GUIDs sind geordnet und sehr schnell für Inserts/Reads und bieten vergleichbare Geschwindigkeiten wie Identitätsspalten. Alle Vorteile einer Identitätsspalte, aber Sie müssen keine verrückten Replikationsstrategien mit einem GUID verwenden. Mit einer Identitätsspalte tun Sie das. Vorteil GUID.

23voto

Bernhard Kircher Punkte 3992

Wie massimogentilini bereits gesagt hat, kann die Leistung verbessert werden, wenn UuidCreateSequential verwendet wird (beim Generieren der GUIDs im Code). Aber es fehlt offenbar ein Fakt: Der SQL Server (zumindest Microsoft SQL 2005 / 2008) verwendet die gleiche Funktionalität, ABER: Die Vergleichs-/Sortierreihenfolge von GUIDs unterscheidet sich in .NET und auf dem SQL Server, was immer noch mehr E/A verursachen würde, da die GUIDs nicht korrekt geordnet werden. Um die GUIDs für den SQL Server richtig geordnet zu generieren, müssen Sie Folgendes tun (siehe Vergleich Details):

[System.Runtime.InteropServices.DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(byte[] buffer);

static Guid NewSequentialGuid() {

    byte[] raw = new byte[16];
    if (UuidCreateSequential(raw) != 0)
        throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error());

    byte[] fix = new byte[16];

    // reverse 0..3
    fix[0x0] = raw[0x3];
    fix[0x1] = raw[0x2];
    fix[0x2] = raw[0x1];
    fix[0x3] = raw[0x0];

    // reverse 4 & 5
    fix[0x4] = raw[0x5];
    fix[0x5] = raw[0x4];

    // reverse 6 & 7
    fix[0x6] = raw[0x7];
    fix[0x7] = raw[0x6];

    // all other are unchanged
    fix[0x8] = raw[0x8];
    fix[0x9] = raw[0x9];
    fix[0xA] = raw[0xA];
    fix[0xB] = raw[0xB];
    fix[0xC] = raw[0xC];
    fix[0xD] = raw[0xD];
    fix[0xE] = raw[0xE];
    fix[0xF] = raw[0xF];

    return new Guid(fix);
}

oder dieser Link oder dieser Link.

1 Stimmen

Toller Punkt. So wie ich es verstehe, könnte die Leistung mithilfe Ihres Codes noch etwas verbessert werden, früher oder später werde ich einige Tests durchführen

4 Stimmen

5voto

Bryon Punkte 51

Siehe diesen Artikel: (http://www.shirmanov.com/2010/05/generating-newsequentialid-compatible.html)

Auch wenn MSSql diese Funktion verwendet, um NewSequencialIds zu generieren ( UuidCreateSequential(out Guid guid) ), kehrt MSSQL die 3. und 4. Byte-Muster um, was nicht das gleiche Ergebnis ergibt, das Sie erhalten würden, wenn Sie diese Funktion in Ihrem Code verwenden würden. Shirmanov zeigt, wie man die genau gleichen Ergebnisse erhält, die MSSQL erstellen würde.

5voto

Alex Siepman Punkte 2359

Ich habe den Unterschied zwischen Guid (geclustert und nicht geclustert), Sequential Guid und int (Identität/Autoinrement) unter Verwendung von Entity Framework gemessen. Der Sequential Guid war überraschend schnell im Vergleich zu int mit Identität. Ergebnisse und Code des Sequential Guid hier.

0 Stimmen

Ergebnisse nicht gefunden. Ich wäre daran interessiert, wie Sie den Unterschied gemessen haben. Das Problem mit Standard-Guidelines, die oft verwendet werden, wären Seitenaufteilungen bei Einfügungen, die langsam die Abfrageleistung beeinträchtigen würden. Haben Sie die Einfügungen so durchgeführt, dass Seitenaufteilungen verursacht wurden?

1 Stimmen

Die URL wurde aktualisiert, damit Sie die Ergebnisse sehen können.

0 Stimmen

Vielen Dank. Eine sehr interessante Analyse. Es wäre großartig, so etwas zu machen, aber dann Abfrage, um zu sehen, wie fragmentiert jede Tabelle ist. Und dann vergleichen Sie eine Abfrage auf einer stark fragmentierten Guid-Tabelle mit einer nicht eindeutigen int-Tabelle. Ich bin derzeit dabei, Guids in COMB-Guids umzustellen in der Hoffnung, dass sich die Abfrageleistung dadurch verbessert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X