Wir erwägen, eine gemeinsame Sequenz zu verwenden, um Primärschlüsseln für alle Tabellen in unserer Datenbank IDs zuzuweisen. Es gibt ungefähr 100 von ihnen. Nur ein paar werden häufig und regelmäßig eingefügt. Wir möchten ausschließen, dass es "aus einem offensichtlichen Grund eine schreckliche Idee" ist, bevor wir uns der Phase zuwenden, in der wir es tatsächlich ausprobieren und unter Last testen.
Unsere Spitzenlast liegt in der Größenordnung von 1000 Einsätzen pro Sekunde über mehrere Tabellen hinweg.
Unsere bisherigen Untersuchungen zeigen, dass - Sequenzgenerierungsgeschwindigkeit kein Problem sein sollte - Sequenzfragmentierung (Lücken) auftreten wird, aber kein Problem sein sollte - ID-Erschöpfung kein Problem sein wird
Wir sind uns nicht sicher, ob wir andere große Dinge vermissen. Wir wären dankbar für die Meinungen der Menschen, insbesondere von Menschen, die es schon einmal versucht haben und entweder positive oder negative Erfahrungen gemacht haben.
Für den Kontext haben wir zwei Hauptmotive dafür.
Eine Motivation dafür ist, dass wir eine Reihe von Wörterbüchern definieren können (wir nennen sie Bereiche) und diesen IDs von Menschen lesbare Wörter zugewiesen bekommen. Daher möchten wir sicherstellen, dass sich IDs in verschiedenen Tabellen niemals überschneiden. In einem Bereich kann der ID 12345 der Wert "Grün" und in einem anderen Bereich "Verde" zugewiesen werden. (Eigentlich verwenden wir es nicht für die Internationalisierung, aber wir könnten eines Tages).
Die andere Motivation besteht darin, es einfach zu machen, mehrere Bereitstellungen vor Ort zu haben und zu wissen (indem Sie die Reihenfolge der wichtigsten Ziffern jeder Bereitstellung eindeutig festlegen), dass sich unsere Bereitstellungen nicht mit Primärschlüsseln überschneiden. (Wie ein GUID Lite).
quelle
Antworten:
Drei mögliche Probleme, die mir in den Sinn kommen, sind:
Mit jeder gemeinsam genutzten Ressource schaffen Sie einen potenziellen Engpass. Mein Bauch sagt, dass dies für Ihre Spitzenlast kein Problem sein sollte, aber ich empfehle dringend, eine solche Lösung in einer produktionsähnlichen Produktionsgröße zu vergleichen, um sicherzugehen.
Sie weisen Ersatzschlüsseln im Wesentlichen eine Bedeutung zu, die einen Teil ihres Zwecks in der RDB-Theorie zunichte macht. Ein Ersatzschlüssel sollte von Natur aus keine Bedeutung haben, die über die Identifizierung von Tupeln in dieser Beziehung hinausgeht. Wenn die Entitäten zusammen eine Bedeutung haben und daher kollisionsfreie Schlüssel benötigen, ist es richtig, dass sie separat modelliert werden, oder wurde etwas in den Anforderungen und / oder im Datenmodelldesign übersehen?
Sie führen einen potenziellen Fehlerpunkt ein. Was ist, wenn für eine Bereitstellung der Startpunkt für die anfängliche Sequenz nicht festgelegt wird? Sie haben dann entweder einen Fehler beim Blockieren der Bereitstellung oder die Bereitstellung beginnt an derselben Stelle, an der Ihre Funktion "beschädigt" wird. Was werden Sie auch tun, wenn irgendwo auf der ganzen Linie jemand der Meinung ist, dass es eine gute Idee ist, eine Bereitstellung zu verzweigen (in der Produktion veräußert möglicherweise ein Mandantenunternehmen einen Teil von sich selbst und muss die Daten trennen). Was ist, wenn der Startwert durch eine fehlerhafte Upgrade-Bereitstellung oder eine andere Migration zurückgesetzt wird? [0]
Wenn Sie keines dieser Probleme betrifft, wird die Idee IMO nicht zerstören. Natürlich kann es bessere Wege geben, auch wenn dieser an sich nicht falsch ist.
Wenn Sie "UUID-lite" sagen, implizieren Sie, dass Sie UUIDs bereits berücksichtigt und abgezinst haben. Ist das der Fall und wenn ja, gibt es bestimmte Gründe für die Entscheidung, dass sie für dieses Projekt nicht geeignet sind?
Ein möglicher Grund für die Nichtverwendung von UUIDs ist die Indexfragmentierung, obwohl deren Bedeutung häufig stark überbewertet ist [1] . Die Antwort von SQL Server darauf ist die "sequentielle GUID", die ziemlich genau dem entspricht, was Sie vorschlagen, wenn wir die Zuweisung von Bedeutung zu Schlüsselwerten nicht berücksichtigen - vielleicht hat postgres eine Entsprechung dazu? Natürlich können immer größere Indizes ihre eigenen Leistungsprobleme haben (Konflikte auf der letzten Seite, Indexstatistiken werden immer veralteter), und zwar bei einigen sehr spezifischen Workloads mit hohem Volumen [2] .
Ein weiteres häufiges Argument gegen UUIDs ist die Schlüssellänge: Warum 16 Bytes pro Wert verwenden, wenn 4 oder 8 ausreichen? Wenn die Einzigartigkeit wirklich eine nützliche Eigenschaft ist, wird dies in der Regel die Bedenken hinsichtlich der Schlüsselgröße erheblich übertreffen. Wenn die Schlüsselgröße ein Problem darstellt, Sie jedoch gerne eine 64-Bit-INT verwenden, anstatt innerhalb von 32-Bit zu bleiben, können Sie Ihre Technik verwenden, ohne ein potenzielles Problem mit Konflikten mit gemeinsam genutzten Ressourcen hinzuzufügen, indem Sie Ihre Idee für einen gesetzten Ganzzahlschlüssel ausführen pro Tabelle [3] unter Verwendung einer normalen
INT IDENTITY(<start>, 1)
[4] Spaltendefinition, obwohl dies wiederum die Komplexität der Bereitstellung erhöht (eine kleine Menge, aber sicherlich nicht Null).Die menschliche Lesbarkeit wird manchmal als Problem angeführt, aber das geht zurück auf die Zuweisung von Bedeutung zu Ersatzschlüsseln.
Komprimierbarkeit ist ein weniger verbreitetes Problem, auf das Sie jedoch möglicherweise stoßen. Für nahezu jeden Komprimierungsalgorithmus sehen UUIDs wahrscheinlich wie zufällige (daher nicht komprimierbare) Daten aus, es sei denn, Sie verwenden so etwas wie die sequentiellen UUIDs von SQL Server. Dies kann ein Problem für eine sehr große Anzahl von Links (oder anderen Datenblöcken) sein, die viele Entitäts-IDs enthalten, die einer Anwendung über ein langsames Netzwerk bereitgestellt werden, oder wenn Sie beispielsweise die Indexkomprimierungsfunktionen von SQL Server verwenden müssen, obwohl beides von Bedeutung ist Im Wesentlichen wird das Problem der Schlüsselgröße nur auf eine etwas andere Art und Weise neu formuliert, und auch hier können sequentielle UUIDs hilfreich sein.
[0] Dies könnte natürlich auch für normale Identitätsspalten passieren, aber da Sie eine weniger verbreitete Funktion verwenden, erhöhen Sie die Wahrscheinlichkeit eines weniger erfahrenen DBA, nachdem Sie das Problem verpasst haben, wenn es passiert, wenn Sie etwas Neues und Aufregendes tun anderswo!
[1] Ich bin ein SQL Server-Typ. Ich vermute, dass das potenzielle Problem bei Postgres dasselbe ist, aber soweit ich weiß, hat es möglicherweise ein anderes Indexlayout, das den Effekt abschwächen kann.
[2] Auch hier kann es sich um SQL Server-spezifisch handeln, insbesondere um das letztere der beiden von mir aufgelisteten Beispiele
[3] Die ersten beiden Bytes: variieren je nach Datenbank, die nächsten beiden: variieren je nach Tabelle, die restlichen vier: die inkrementierenden Bits
[4] Das ist die MS SQL Server-Syntax. Die Postgres-Syntax kann variieren, aber Sie sollten sehen, was ich meine, und in der Lage sein, zu übersetzen
tl; dr: Wenn Sie feststellen, dass Sie das Rad neu erfinden, stellen Sie sicher, dass alle vorhandenen Designs wirklich nicht geeignet sind, bevor Sie überlegen, warum ein neues möglicherweise vorhanden ist oder nicht.
quelle
Das ist eine schreckliche Idee: Ausschluss. Verwenden Sie einfach eine GUID / UUID. Warum haben Sie diese Idee ausgeschlossen? In PostgreSQL verwenden wir
uuid-ossp
:So was,
Sie machen in Ihrer Antwort viele Annahmen, damit sie gültig ist.
Sie müssen nichts davon annehmen. Was ist, wenn Sie ein DOS auf der ID erhalten, das eine massive Lücke erzeugt und einen Rollover auf einen Shard drückt? Warum nicht einfach die Branchenlösung für dieses Problem verwenden? Es ist nicht klar, dass es einen einzigen Nachteil gibt. Es ist wahrscheinlich alles zu gewinnen. Bis auf ein paar Bytes Speicher.
quelle
Allein würde ich nicht zulassen, dass dies der Grund für die Wahl eines skurrilen und fragilen Designs ist. Wenn Sie den Weg gehen, gibt es keine Möglichkeit, die Datenbankfunktionen zu nutzen, um beispielsweise die referenzielle Integrität sicherzustellen. Ein traditioneller normalisierter Weg, um dasselbe zu erreichen, hätte Vorteile, die über RI hinausgehen:
dbfiddle hier
Ich würde vorschlagen, wie andere es getan haben, dass die Verwendung von UUID viel besser (dh viel weniger fehleranfällig) ist als die Erfindung einer neuen UUID-Lite.
Ich denke immer noch nicht, dass dies die beste Wahl ist - Sie sind nicht am Splittern, sodass zwischen den Bereitstellungen keine nicht überlappenden IDs erforderlich sind, die ich anhand der von Ihnen bereitgestellten Informationen sehen kann. Vermutlich haben Sie andere Möglichkeiten, eine Bereitstellung in einer Datenbank zu identifizieren, als die IDs in diesen Tabellen zu betrachten.
quelle
Ich habe das von Ihnen vorgeschlagene Muster mit einer zusätzlichen zentralen ID-Tabelle verwendet, für die alle anderen IDs Fremdschlüssel sind. Es funktionierte in einem großen Produktionssystem völlig in Ordnung.
Ich denke, der wahre Grund dafür ist, dass Ihre IDs einen Bereich haben, der über Ihre Datenbank hinausgeht. In meinem Beispiel wurden in diesen IDs beispielsweise eindeutige finanzielle Wertpapiere und Unternehmen aufgeführt. Sie könnten sich fragen, warum Sie nicht einen Satz if-IDs für Unternehmen und einen zweiten Satz für Wertpapiere als Primärschlüssel für die automatische Zuordnung für jede Tabelle erstellen sollten. Weil wir wollten, dass sich andere Zeitreihenaufzeichnungen entweder auf Wertpapiere oder auf Unternehmen beziehen. Die Fremdreihenfolge der Zeitreihentabelle ist also mit der zentralen ID-Tabelle verknüpft.
In Anbetracht dessen würde eine GUID / UUID auch gut funktionieren. Diese Formate haben jedoch häufig eine Größe von 128 Bit, was sich auswirken kann, da sie in fast allen Indizes, Primärschlüsseln und Fremdschlüsseln der Datenbank verwendet werden zu suboptimaler Auswahlleistung. Unsere Datenbank war sehr darauf ausgerichtet, die Leistung auszuwählen.
GUIDs / UUIDs haben einen Vorteil: Sie lassen sich viel einfacher mit Verbundgenerierungsprozessen erstellen. Das heißt, Sie können mehrere ID-Generierungs- / Zuweisungsprozesse in Ihrem Unternehmen ohne Koordination durchführen, indem Sie einfach davon ausgehen, dass sie niemals in Konflikt geraten. Wenn sich Ihre einzigen ID-Generierungsprozesse in Ihrer Datenbank befinden, ist dies weniger bedenklich, aber erwähnenswert.
Beachten Sie, dass die UUID-Generierung davon abhängt, dass Ihre MAC-Adressen eindeutig sind. Daher müssen Sie dies in einer virtuellen / Container-Umgebung berücksichtigen.
quelle