Sequentielle GUID oder Bigint für 'sehr große' Datenbanktabelle PK

14

Ich weiß, dass diese Art von Frage häufig gestellt wird, aber ich habe noch keine überzeugenden Argumente gelesen, um diese Entscheidung treffen zu können. Bitte bei mir tragen!

Ich habe eine riesige Datenbank - sie wächst um ungefähr 10.000.000 Datensätze pro Tag. Die Daten sind relational und aus Performancegründen lade ich die Tabelle mit BULK COPY. Aus diesem Grund muss ich Schlüssel für die Zeilen generieren und kann mich nicht auf eine IDENTITY-Spalte verlassen.

Eine 64-Bit-Ganzzahl - eine Ganzzahl - ist für mich ausreichend breit, aber um die Eindeutigkeit zu gewährleisten, benötige ich einen zentralen Generator, um meine IDs für mich zu erstellen. Ich habe derzeit einen solchen Generatordienst, der es einem Dienst ermöglicht, X-Sequenznummern zu reservieren und garantiert, dass keine Kollisionen auftreten. Dies hat jedoch zur Folge, dass alle Dienste, die ich habe, auf diesen einen zentralen Generator angewiesen sind. Daher kann ich mein System nur eingeschränkt verteilen und bin nicht zufrieden mit den anderen Abhängigkeiten (z. B. der Anforderung eines Netzwerkzugriffs) durch diesen Entwurf. Dies war gelegentlich ein Problem.

Ich überlege jetzt, sequentielle GUIDs als meine Primärschlüssel zu verwenden (extern für SQL generiert). Soweit ich anhand meiner eigenen Tests feststellen konnte, besteht der einzige Nachteil darin, dass ein größerer Datentyp mehr Speicherplatz benötigt (was durch die Verwendung in Indizes noch verstärkt wird). Ich habe keine erkennbare Verlangsamung der Abfrageleistung im Vergleich zur Bigint-Alternative festgestellt. Das Laden des Tisches mit BULK COPY ist etwas langsamer, aber nicht viel. Meine GUID-basierten Indizes werden dank meiner sequentiellen GUID-Implementierung nicht fragmentiert.

Grundsätzlich möchte ich wissen, ob es andere Überlegungen gibt, die ich möglicherweise übersehen habe. Im Moment bin ich geneigt, den Sprung zu wagen und GUIDs zu verwenden. Ich bin kein Datenbankexperte, daher würde ich jede Anleitung wirklich begrüßen.

Barguast
quelle
2
Wie würden Sie eine "sequentielle GUID" generieren?
Es ist eine benutzerdefinierte Implementierung. Grundsätzlich handelt es sich um ein GUID-Format, bei dem 6 Bytes durch Zeitstempelbytes ersetzt werden und 2 Bytes eine Folgenummer darstellen, bei der der Zeitstempel identisch ist. Es ist nicht garantiert, dass perfekte sequentielle Werte erzeugt werden, aber es ist gut genug, um die Indexfragmentierung für mich zum Nullpunkt zu machen.
Laden Sie diese Daten daher aus mehreren verschiedenen Quellen? Ich gehe auch davon aus, dass der Index, um den Sie sich Sorgen machen, der Clustered-Index ist.
2
Wenn Sie mit einer sequentiellen GUID arbeiten, sollten Sie sich NEWSEQUENTIALID () ansehen. Es sollte tun, was Sie wollen (monoton steigend) und nicht auf benutzerdefinierten Code angewiesen sein.
2
Schauen Sie sich den Beitrag von Jeremiah Peschka über Das Problem mit den Schlüsseln an .
Billinkc

Antworten:

4

Ich bin in einer ähnlichen Situation. Derzeit verwende ich den sequentiellen GUID-Ansatz und habe keine Fragmentierung und einfache Schlüsselgenerierung.

Ich habe zwei Nachteile festgestellt, die mich veranlasst haben, auf bigint umzusteigen:

  1. Raumnutzung . 8 Bytes mehr pro Index. Multiplizieren Sie das mit 10 oder mehr Indizes, und Sie erhalten eine enorme Verschwendung von Speicherplatz.
  2. Columnstore- Indizes unterstützen keine GUIDs.

(2) War der Mörder für mich.

Ich werde jetzt meine Schlüssel so generieren:

yyMMddHH1234567890

Ich werde ein führendes Datum plus Stunde verwenden und danach einen sequentiellen Teil haben . Dadurch kann ich meine Daten nach Datum abfragen, ohne dass ein zusätzlicher Index erforderlich ist. Das ist ein schöner Bonus für mich.

Ich werde den sequentiellen Teil der Bigint mit einem HiLo- Algorithmus generieren, der sich gut für die Verteilung eignet .

Hoffe, dass ein Teil davon auf Ihre Situation übertragen wird. Ich empfehle auf jeden Fall die Verwendung von Bigint.

usr
quelle
1
Markieren Sie dies als die "Antwort", da es am besten passt (und Sie scheinen zu schätzen, was ich frage und warum dies nicht so einfach ist, wie es zuerst erscheinen mag). Ich glaube, ich werde mit einem gemeinsamen Sequenzgenerator arbeiten (der ähnlich wie Ihr Vorschlag für einen HiLo-Algorithmus funktioniert). Ich habe diese Arbeit auf einem anderen System mit wenigen Problemen, ich muss mich nur mit der zusätzlichen Abhängigkeit abfinden. Naja. Vielen Dank.
Barguast
3

Mit einem Typ INT, der bei 1 beginnt, erhalten Sie über 2 Milliarden mögliche Zeilen - das dürfte für die überwiegende Mehrheit der Fälle mehr als ausreichend sein. Mit BIGINTbekommen Sie ungefähr 922 Billiarden (922 mit 15 Nullen - 922'000 Milliarden) - genug für Sie?

Wenn Sie eine INT IDENTITYbeginnend bei 1 verwenden und jede Sekunde eine Zeile einfügen, benötigen Sie 66,5 Jahre, bevor Sie das 2-Milliarden-Limit erreichen.

Wenn Sie BIGINT IDENTITYbei 1 beginnen und jede Sekunde tausend Zeilen einfügen, brauchen Sie 292 Millionen Jahre, bevor Sie die Grenze von 922 Billiarden erreichen.

Wenn Sie Ihre 10 Millionen Zeilen pro Tag verwenden, haben Sie genug Daten für ungefähr 1'844'674'407'370 Tage ( 1844 Milliarden Tage oder ein Tick über 5 Milliarden Jahre ) - das ist gut genug für Ihre Bedürfnisse ?

Weitere Informationen (mit allen verfügbaren Optionen) finden Sie in der MSDN-Onlinedokumentation .

marc_s
quelle
1
Die Einfügungsrate von 10 Millionen Zeilen pro Tag würde den INT-Bereich in 200 Tagen erschöpfen.
Mceda
@mceda: ja - habe ich noch etwas behauptet? Es erschöpft die BIGINTReichweite nicht so schnell ...
marc_s
Danke, aber wie ich in meiner Frage sagte, brauche ich die IDs, bevor sie an die Datenbank gesendet werden. Die Daten sind relational, daher muss ich Primär- und Fremdschlüssel zuweisen, bevor sie massenhaft kopiert werden. Ohne das wäre ein IDENTITY BIGINT wahrscheinlich perfekt.
2
@Barguast: Könnten Sie Ihre Daten nicht einfach als Masseneintrag in eine Staging-Tabelle (ohne Identität) einfügen und von dort aus mit in Ihre eigentlichen Datentabellen verschieben BIGINT IDENTITY?
marc_s
@marc_s: Ja, die angegebene Berechnung wurde nicht mit der Frage abgeglichen: "Wenn Sie eine INT IDENTITY ab 1 verwenden und jede Sekunde eine Zeile einfügen, benötigen Sie 66,5 Jahre, bevor Sie das 2-Milliarden-Limit erreichen."
Mceda
2

Ich empfehle Ihnen, in SQL 2012 den Datentyp SEQUENCE of BIGINT zu verwenden. Dies ist viel flexibler als IDENTITY mit Optionen wie Cache / Nocache. Sie können auch einen Sequenzbereich für Ihre Batch-Operation als sp_sequence_get_range zuweisen.


quelle
Leider wird SEQUENCE unter Sql Azure nicht unterstützt.
Timothy Lee Russell
2

Ist der Grund, warum Sie IDENTITY nicht verwenden können, weil bereits Fremdschlüsselbeziehungen zwischen separaten Tabellen bestehen, die Sie laden? Und es gibt keinen anderen natürlichen Schlüssel für Sie, um sie in einem Vorgang von einem Bereitstellungsbereich zum Produktionsbereich zu verknüpfen? Aus diesem Grund würde ich gerne ein bisschen mehr darüber erfahren, wie sie derzeit im Quellsystem "verknüpft" sind, bevor Sie eine Massenkopie erstellen. Verwenden mehrere Quellsysteme einfach ihre eigenen Sequenzen und haben die Möglichkeit von Konflikten, wenn sie in eine gemeinsam genutzte Datenbank gebracht werden?

Die COMB-ID / sequentielle GUID-Technik ist mir vertraut und kann immer dann verwendet werden, wenn Sie die globale Eindeutigkeit benötigen, die außerhalb der Datenbank zugewiesen wurde. Sie ist effektiv eine verwendbare Zeilenidentität sowohl innerhalb als auch außerhalb der Datenbank. Aus diesem Grund ist es in stark verteilten Umgebungen oder getrennten Szenarien eine gute Wahl

Außer wenn Sie es wirklich nicht brauchen, weil dieser zusätzliche Breitenunterschied erheblich ist, wenn die Datengröße zunimmt und diese Schlüssel in jedem Index und in den Arbeitssätzen für viele Abfragen vorhanden sind.

Wenn die Zeilen bei verteilter Generierung nicht tatsächlich in der Reihenfolge der GUID-Spalte vorliegen, können die Probleme bei der Verwendung dieses Schlüssels für den gruppierten Indexschlüssel (eng, statisch, zunehmend) möglicherweise zu einer Fragmentierung führen, die mit der Clusterbildung für eine IDENTITY vergleichbar ist bleiben übrig.

Cade Roux
quelle
0

Im Allgemeinen können mit OUTPUTder INSERTBefehlsklausel Daten in beide Tabellen eingefügt und mit dem Identitätsfeld verknüpft werden.

Kennung, die auf einem Zeitstempel basiert, sollte nicht als zuverlässig angesehen werden - dies hängt von der Systemuhr ab, die wiederum von vielen Dingen abhängt - von der Hardwareuhr bis zu Zeitsynchronisationsdiensten.

Serg
quelle