Erstellen eines sekundären Primärschlüssels in einer Datenbank für einige Tabellen

22

Zu einigen meiner Tabellen möchte ich "second_primary_key" hinzufügen, was uuid oder ein zufälliger langer Schlüssel sein wird. Ich brauche es, weil ich für einige Tabellen keine Ganzzahlen für meine Webanwendung bereitstellen möchte. Das heißt, auf einer Seite "/ invoices" habe ich eine Liste von Rechnungen und einen Link zu "/ invoices /: id", wobei: id eine Ganzzahl ist. Ich möchte nicht, dass ein Benutzer weiß, wie viele Rechnungen sich in meinem System befinden. Daher möchte ich anstelle von "/ invoices / 123" den "second_primary_key" verwenden, damit die URL "/ invoices / N_8Zk241vNa" lautet.

Das gleiche gilt für andere Tabellen, in denen ich die echte ID verstecken möchte.

Ich frage mich, ist das eine gängige Praxis? Wie lässt sich das am besten umsetzen?

Und wie heißt diese Technik überhaupt, damit ich danach suche?

Dari
quelle
20
Warum nicht die ganze Zahl ganz loswerden?
Larsbe
4
Sie können so viele eindeutige Schlüssel / Indizes für eine Tabelle definieren, wie Sie möchten.
abuzittin gillifirca
2
Vielleicht sollten Sie es einen sekundären Kandidatenschlüssel nennen. "Primary" schlägt nur eine vor.
Walter Mitty
4
"Second Primary" ist ein Oxymoron. Sie haben einen Primärschlüssel und Sie können Sekundärschlüssel haben.
Hören Sie auf, Monica
7
@RobbieDee Es gibt gültige Gründe dafür, dass eine Datenbank nicht vollständig normalisiert wurde. Und mit einem Kandidaten oder einem Sekundärschlüssel werden Daten nicht genau dupliziert.
Machado

Antworten:

0

Sie könnten eine UUID-Spalte hinzufügen, müssen dies jedoch nicht (und sollten dies auch nicht). Dies ist ein Anliegen der Präsentationsebene. Sie würden nicht davon träumen zu sagen, einen Währungswert von 1.999 US-Dollar sowie 1999 zu speichern.

Sie möchten nur eine Möglichkeit, den Wert für die Anwendung im Handumdrehen zu verschleiern. Sie können dies entweder in der Anwendung selbst oder als Datenbankansicht tun.

Da es sich nur um einen einzelnen Wert handelt, sollten Sie sich eine Zwei-Wege-Verschlüsselung wie AES oder ähnliches ansehen - je leichter, desto besser.

Hashing könnte eine andere Möglichkeit sein - es hängt davon ab, ob Sie die Rechnungsnummer zurückerhalten möchten, da Hashing eine Möglichkeit ist.

Robbie Dee
quelle
48

Ein "alternativer Primärschlüssel" ist ein bekanntes Konzept in der relationalen Datenbankmodellierung und wird als "alternativer Schlüssel" oder manchmal auch als "Sekundärschlüssel" bezeichnet. Der Satz von "potentiellen Primärschlüsseln" wird "Kandidatenschlüssel" genannt. Siehe https://beginnersbook.com/2015/04/alternate-key-in-dbms/

Wie Sie dies implementieren, liegt ganz bei Ihnen, insbesondere wenn Sie die Gesamtzahl der Datensätze ausblenden möchten. Es gibt keinen "besten Weg", Sie sollten Ihre Anforderungen wie zulässiger oder nützlicher Zeichensatz, maximale Länge überprüfen, ob bei den IDs die Groß- und Kleinschreibung beachtet werden soll oder nicht, wenn Sie möchten, dass sie auf einer gedruckten Rechnung lesbar sind, falls jemand Sie müssen in der Lage sein, sie am Telefon fehlerfrei zu beantworten, und so weiter.

Doc Brown
quelle
11
Ich habe auch die Begriffe Natural Key vs. Surrogate Key gesehen, die zur Beschreibung dieses Szenarios verwendet werden.
DanK
2
@Dari: Sie haben gefragt, wie diese Technik heißt - in Fettdruck. Und wenn die AES-Entschlüsselung - möglicherweise im laufenden Betrieb - die von Ihnen gesuchten Schlüssel hervorbringt, verwenden Sie sie, was meiner Antwort nicht widerspricht.
Doc Brown
1
@Dari Weil es Ihrer App einen völlig unnötigen Overhead hinzufügt
Lamak
1
@RobbieDee Wir haben bereits erfahren, dass Sie alternative Schlüssel nicht mögen, aber das bedeutet nicht, dass sie unbrauchbar sind. Ich mag den Guid-Ansatz, weil er viele Probleme vereinfacht.
T. Sar - Reinstate Monica
1
@RobbieDee Wir verwenden keinen SQL Server. Wir verwenden MySQL. Und das passiert, weil jemand etwas auf Prod erstellt, sagen wir mit der ID 1234. Auf Dev machen wir natürlich viel mehr Entities als auf prod. 1234 wurde vor langer Zeit von einer Wegwerfeinheit zum Testen genommen. Wenn wir eine Entität von prod aus testen müssen, müssen wir sie zurück nach Dev migrieren - und ihr Primärschlüssel wird bereits verwendet. Die Migration ist viel einfacher, wenn Verweise auf diese Entität auf einer Guid basieren. Der Ruhezustand funktioniert jedoch viel besser, wenn ein Primärschlüssel int oder long ist. Das behalten wir also bei. Meine Entwickler sind nicht faul oder unwissend - sie sind erfahren.
CorsiKa
9

Die meisten Rechnungen haben eine Rechnungsnummer, die nach den meisten Abrechnungsregeln fortlaufend sein muss, oder ein Buchhalter kann die Jahresergebnisse nicht abzeichnen, oder die IRS (oder eine ähnliche in Ihrem Land) möchte eine vollständige Prüfung Ihrer Registerkarten durchführen.

Ein Benutzer konnte aus der Rechnungsnummer ableiten, wie viele Kunden Sie bedient haben oder wie lange es gedauert hat, bis Sie die Nummerierungsstrategie für Rechnungen geändert haben.

Wie viele Rechnungen in der Datenbank gespeichert sind, ist kein Maß für die Gesamtsumme Ihrer Rechnungen. Sie können dies auch auf andere Weise herausfinden, indem Sie Ihre Jahresberichte bei der Handelskammer anfordern.

Ich würde jedoch die Rechnung hinter einem Benutzeranmeldebildschirm sperren, damit nicht jeder sie anfordern kann. Bei der Benutzeranmeldung können sie dann mithilfe einer Ajax-Methode ihre ausstehenden Rechnungen usw. anfordern. Dies sichert Ihre Daten, verbirgt die URL durch Ajax (normalerweise kann sich niemand die Mühe machen, die Details zum Aufbau der Ajax-Anforderung zu prüfen). und Sie steuern, wie die Daten angezeigt und angeboten werden.

Tschallacka
quelle
7
Eine im Bankgeschäft übliche Strategie (mit Schecknummern) besteht darin, die inkrementelle Zählung nicht bei 1 zu beginnen, sondern aus genau diesem Grund bei einer größeren Zahl.
DanK
Ich denke, das ist der Grund, warum die ID ein zusätzlicher Primärschlüssel sein soll, kein Ersatz für den alten Primärschlüssel.
Alexander
1
Ich würde es nicht als Primärschlüssel bezeichnen. Ich würde mich für einen Slug entscheiden, eine UUID als Namen, aber im Grunde ist es nur ein weiteres indiziertes Feld in der Tabelle. Angebots-ID, Rechnungsnummer, was auch immer. Es ist ein Feld, aber kein Primärschlüssel. Ein Primärschlüssel muss eindeutig sein und kann intern für die relationale Zuordnung verwendet werden. Wenn das Feld indiziert ist, kann es mit einer where-Abfrage schnell durchsucht werden. userXveryY.where ('rechnungsnummer', 'foobarbaz10'). get ();
Tschallacka
1
Sie beantworten eine technische Frage mit einem Argument, das aufgrund von Besonderheiten in den USA nicht erforderlich ist (erforderliche fortlaufende Rechnungsnummern, Berichte bei der Handelskammer). IMO das beantwortet die Frage nicht gut.
RemcoGerlich
7

Möglicherweise können Sie dafür Hash-IDs verwenden . Sie wurden entwickelt, um genau dieses Szenario zu lösen.

Ihre Datenbank-ID wird in einem kurzen Hash (ähnlich der URL eines YouTube-Videos) codiert, und Sie müssen Ihrer Tabelle keine sekundären Schlüssel hinzufügen.

mitchdav
quelle
2
Der Name ist etwas irreführend, da es sich nicht um einen Hash handelt, sondern um eine umkehrbare Funktion. Aber es scheint die perfekte Lösung für das Problem zu sein.
Crazy Yoghurt
2
@ CrazyYoghurt Richtig ... sie haben den Grund für die Nennung wie hier angesprochen
Eric King
3

Sie können einen anderen eindeutigen Schlüssel erstellen, dies sollte jedoch nicht der Fall sein. Nicht aus dem angegebenen Grund. Es gibt einfachere Möglichkeiten, die Tischgrößen auszublenden.

Das Speichern N_8Zk241vNakostet 12 Byte pro Zeile in der Tabelle und noch mehr im Index. Das ist ziemlich verschwenderisch für das, was Sie brauchen.

Das Verschlüsseln der Ganzzahl idkostet Sie keinen Platz und fast nichts in der Laufzeit. Wie Sie dies tun, hängt von Ihrer Programmiersprache und / oder Ihrer Datenbank ab.

Beachten Sie, dass Sie mit AES eine 128-Bit-Ganzzahl erhalten, was 22 Zeichen in base64 bedeutet, wahrscheinlich mehr als Sie möchten. Eine Verschlüsselung mit einer Blockgröße von 64 wie DES oder 3DES gibt Ihnen 11 Zeichen, ganz wie Sie möchten.

Verwenden Sie unterschiedliche Schlüssel für unterschiedliche Tabellen.

Wenn Sie nur die Tabellengrößen ausblenden müssen, können Sie für alle Tabellen eine gemeinsame Reihenfolge verwenden. Beachten Sie, dass es zu Engpässen kommen kann, wenn viele Ihrer Tabellen häufig eingefügt werden. Mit etwas wie Ruhezustand und einem Hi-Lo-Algorithmus verschwindet dieses Problem.

maaartinus
quelle
Genau - diesen Wert zu speichern, nur um einen anderen auszublenden, ist einfach falsch.
Robbie Dee
In diesem Szenario funktioniert dies möglicherweise, da eine Rechnungs-ID nicht wirklich vertraulich ist. Die Verwendung vertraulicher IDs als relationale Struktur in einer Datenbank bereitet jedoch in der Regel Kopfschmerzen, wenn Sie zu einem späteren Zeitpunkt Daten maskieren müssen. Besser, sie als Attribut zu behandeln.
DanK
Wie kann ich mich hier bewerben?
Dari
@Dari Wie kannst du AES auf irgendetwas anwenden ? Ohne Ihre Sprache zu kennen, kann niemand sagen. Normalerweise arbeitet AES mit a byte[], Sie können Ihre idin vier oder acht Bytes schreiben , eine eindeutige Tabellennummer hinzufügen und verschlüsseln (die Eingabe muss genau 16 Bytes sein). Wenn Sie zwischen verschiedenen Modi wählen können, ist die EZB richtig.
Maaartinus
@ DanK Was? Behaupten Sie, dass AES unsicher ist? Ohne den Schlüssel zu kennen, gibt es nichts, was der Angreifer besser machen könnte als für ein gespeichertes Attribut. Nichts. +++ Ich glaube, ich verstehe deinen Kommentar nicht.
Maaartinus
0

IMHO Erstellen von zwei verschiedenen Primärschlüsseln ist nicht möglich. Natürlich können Sie diese UUID in eine DB einfügen, um sie als "Alias" für den aktuellen Primärschlüssel zu haben. Sie können einen Index mit einer eindeutigen Einschränkung über dieser Spalte platzieren, der Primärschlüssel ist jedoch (von Grund auf) ein einzelner Index in einer einzelnen Tabelle. Es kann einen zusammengesetzten Primärschlüssel geben, aber das ist nicht das, wonach Sie suchen.

Also schlage ich vor, es dort abzulegen, aber nur mit Index. Sie können eine Handling-Komponente für die Abfrage von Daten nach PK sowie für andere eindeutige Spalten erstellen. Wenn Sie eine Anfrage nach "/ invoices / ..." bearbeiten, überprüfen Sie einfach den Parameter. Wenn es sich um eine Ganzzahl handelt, suchen Sie die ID, andernfalls suchen Sie die UUID. Oder Sie können die UUID-Suche als Ersatz verwenden, wenn die ID-Suche nichts gefunden hat.

Und um ein paar "zufällige" UUIDs zu generieren: Warum nicht so etwas wie "ID nehmen, CONSTANT hinzufügen, in Hexadezimalzahl konvertieren". Die Eindeutigkeit der ID gibt die Eindeutigkeit der UUID an. Die hexadezimale Zahl ist für normale Sterbliche schwerer zu lesen. Durch das Hinzufügen einer Konstanten wird vermieden, dass die UUID 00000001 entspricht.

Jarda
quelle
1
"Warum nicht so etwas wie" ID nehmen, CONSTANT hinzufügen, in Hexadezimal umwandeln "- weil das ziemlich einfach herauszufinden ist - gib mir eine URL und ich werde mir alle anderen Rechnungen im System ansehen. IMO gibt es kein Problem dass dies tatsächlich löst, nur diejenigen, die es möglicherweise erstellt
CompuChip
Wenn Anfrage Handhabung für‚/ Rechnungen / ...‘nur die Parameter überprüfen - wenn es ganze Zahl ist, die ID suchen , sonst sucht UUID “ Der springende Punkt (wie ich die Frage verstehe) ist jemand Suche nach ID zu verhindern ( /invoices/123, /invoices/124, ...) Sie würden also nur nach UUID über die URL suchen.
TripeHound
Außerdem enthalten nicht alle Hexadezimalzahlen Buchstaben. Es ist unmöglich, immer zwischen Ihren zugrunde liegenden Ganzzahlen und Ihren generierten Hex-Zahlen zu unterscheiden.
TRiG
@CompuChip Sie interessieren sich erwartungsgemäß für Computer :-), damit Sie die Hex-Zahl auf den ersten Blick erkennen. Das Q wurde jedoch so geschrieben, dass die Rechnungsnummer nicht direkt angezeigt wird, damit andere wissen, wie viele Rechnungen es gibt. Wenn ich meiner Frau, Mutter oder Nachbarin eine Hex-Zahl zeige, wissen sie nicht, was dieser "seltsame Text" ist. Wenn aufgrund der Rechnungsnummern im Q eine Sicherheitsmitteilung angezeigt wird, empfehle ich eine komplexe Hashmethode für diesen Zweck.
Jarda
@ TripeHound er könnte immer noch in der Lage sein, intern oder innerhalb eines zugriffsbeschränkten Einstiegspunkts nach ID zu suchen ...
Jarda
0

Wenn beide Tasten auf dieselbe Tatsache verweisen und niemals kollidieren würden. Warum nicht den anderen Schlüssel mit einer Skalarfunktion vom Original ableiten, die einen benutzerdefinierten Hash-Code Ihres Originalschlüssels erzeugt?

Alternativ können Sie eine Anhang-Zuordnungstabelle erstellen, in der beide Versionen des Schlüssels gespeichert werden. Diese Tabelle dient als Wörterbuch zum Nachschlagen des Sekundärschlüssels.

Nach meinem Verständnis sind Schlüssel implizite Indizes, und je mehr Sie Indizes hinzufügen, desto langsamer werden die Einfügungen.

A.Rashad
quelle
+1 Ja, das Hinzufügen einer möglicherweise großen Zeichenfolgenspalte mit einem Index ist sicherlich nicht die wertfreie Operation, die andere vorschlagen. Wenn Indizes hinzugefügt werden, verringert sich die Einfügungsgeschwindigkeit.
Robbie Dee
0

Ein weiterer Ansatz für Ihren speziellen Anwendungsfall besteht darin, dass Sie anstelle einer Änderung der Datenbank und der Anwendung einfach eine benutzerdefinierte Route zu den Rechnungen erstellen können, sodass / invoices /: f (id) wobei f (id) eine Funktion der ID ist.

Die benutzerdefinierte Route ist dafür verantwortlich, eine Anforderung der richtigen Aktion serverseitig zuzuordnen.


quelle
0

Dies ist eine völlig akzeptable Vorgehensweise, die auch als "Alternate Key" (AK) bezeichnet wird. Grundsätzlich ist der AK ein weiterer eindeutiger Index oder eine eindeutige Einschränkung.

Sie können sogar Fremdschlüsseleinschränkungen basierend auf Ihrer AK erstellen.

Ein möglicher Anwendungsfall entspricht dem, was Sie erklärt haben: Sie haben eine gruppierte PK mit einer ständig wachsenden Identitätsnummer, möchten jedoch nicht, dass diese Nummer angezeigt oder als Suchkriterium verwendet wird, da dies einfach erraten werden kann. Sie haben also zusätzlich eine zufällige eindeutige Kennung oder Referenznummer als AK, und das ist die ID, die Sie dem Benutzer präsentieren

Alex Schievink
quelle
0

Es gibt verschiedene Arten von Schlüsseln / Indizes. Ein Primärschlüssel ist ein spezieller eindeutiger Index, und wie die Antworten besagen, können Sie mit Sicherheit einen weiteren eindeutigen Schlüssel erstellen. Und ich bin damit einverstanden, dass es am besten ist, Ihre Datenbankinterna nur dann offenzulegen, wenn es einen sehr guten Grund gibt.

Da die Frage im Zusammenhang mit Rechnungen und Zahlen steht, lohnt es sich möglicherweise zu untersuchen, wie die Buchhaltungsbranche das Aussehen von Rechnungsnummern erwartet: http://smallbusiness.chron.com/assign-invoice-numbers-52422.html

Es mag unsauber erscheinen, eine interne ID zu haben, die ein Primärschlüssel ist, und ein weiteres eindeutiges Feld mit der Rechnungsnummer, die für die Anwendung / den Kunden sichtbar ist. Aber es ist nicht so unrein, wenn der Kunde beispielsweise ein Jahr später ein neues Rechnungsnummerierungsschema einführen möchte. In diesem Fall würden Sie die interne ID und ihre Beziehungen in anderen Tabellen nicht stören, um die gesamte Wachskugel neu zu nummerieren. Sie würden Ihre interne ID beibehalten und die nicht interne Rechnungsnummer neu nummerieren.

Idealerweise bemühen Sie sich, Tabellen auf Schlüsseln / Fremdschlüsseln, die sich wahrscheinlich ändern, nicht miteinander zu verknüpfen, und halten Ihre internen Tabellen und Beziehungen für die App-Ebene transparent.

Thomas Carlisle
quelle
0

Tue es.

Dies unterscheidet sich nicht von einem "Slug" -Feld, über das Blog-Artikel und dergleichen häufig verfügen - eine einzigartige Möglichkeit, auf den Datenbankdatensatz zu verweisen, der vom Primärschlüssel getrennt ist und für die Verwendung in einer URL geeignet ist. Ich habe noch nie jemanden dagegen argumentieren hören.

RemcoGerlich
quelle