Warum wird die Verwendung von String-Schlüsseln allgemein als schlechte Idee angesehen?

23

Das nervt mich schon eine Weile. Wenn es darum geht, Daten in Strukturen wie Hashtabellen, Programmierern, Büchern und Artikeln zu speichern, besteht die meiste Zeit darauf, dass das Indizieren von Elementen in diesen Strukturen nach String-Werten als schlechte Praxis angesehen wird. Bisher habe ich jedoch keine einzige solche Quelle gefunden, um zu erklären, warum dies als schlechte Praxis angesehen wird. Kommt es auf die Programmiersprache an? Auf dem zugrunde liegenden Rahmen? Auf die Umsetzung?

Nehmen Sie zwei einfache Beispiele, wenn es hilft:

Eine SQL-ähnliche Tabelle, in der Zeilen durch einen String-Primärschlüssel indiziert werden.

Ein .NET-Wörterbuch, in dem die Schlüssel Zeichenfolgen sind.


quelle
9
String-Keys zu haben, ist im Allgemeinen keine schlechte Idee. Ich vermute, dass diese Aussagen in einem Kontext gemacht wurden, in dem ein besserer Schlüsseltyp verfügbar ist. Ich habe die ganze Zeit .net-Wörterbücher mit String-Schlüsseln. Können Sie einige Beispiele für diese Behauptung nennen?
CodesInChaos
3
Normalerweise möchten Sie Primärschlüssel, die sich während der Lebensdauer eines Objekts / einer Zeile nicht ändern. So ist beispielsweise usernameder Primärschlüssel einer usersTabelle wahrscheinlich nicht die beste Idee, und Sie würden eine automatische Inkrementierungs-ID bevorzugen. Aber das usernameist eine Zeichenfolge ist nur zufällig, eine veränderbare Eigenschaft ist das Hauptproblem
CodesInChaos
Überlegen Sie in einer Datenbank, wie Zeichenfolgen im Gegensatz zu Ganzzahlen indiziert werden sollen.
@CodesInChaos Ich wünschte, ich könnte mich erinnern, wo ich die meisten Fälle gefunden habe, aber jetzt kann ich das Bit einfügen, das mich an das Problem erinnert. Es war aus einer GDC-Diashow von Valve, in der Spieledialoge und das Speichern von Fakten über die Welt in <key = string, value = object> -Paaren besprochen wurden.
2
Saiten sind in Ordnung. Nur keine "magischen" Saiten. Wenn Sie eine Hash-Tabelle verwenden, stellen Sie sicher, dass Ihr Code keine nackten Zeichenfolgen enthält. Sie sollten große Textwerte als Schlüssel vermeiden, da sie nicht gut funktionieren. In den meisten Situationen der realen Welt ist eine kurze Textzeichenfolge jedoch genauso schnell wie eine Ganzzahl (es handelt sich nicht um massive Datenbanken). Sie können auch alternative Schlüssel verwenden, z. B. ist der Primärschlüssel eine Zahl, aber es gibt auch einen "Slug" oder eine eindeutige Zeichenfolge, die ebenfalls eindeutig ist.
Ipaul

Antworten:

17

Alles hat im Grunde genommen mit den beiden Dingen zu tun:

1) Die Suchgeschwindigkeit (wo zum Beispiel ganze Zahlen viel besser abschneiden)

2) Die Größe der Indizes (wo String-Indizes explodieren würden)

Jetzt hängt alles von Ihren Anforderungen und der Größe des Datensatzes ab. Wenn eine Tabelle oder eine Auflistung 10-20 Elemente enthält, ist der Typ des Schlüssels irrelevant. Es wird sehr schnell auch mit einem String-Schlüssel sein.

PS: Möglicherweise hat dies nichts mit Ihrer Frage zu tun, aber Guids gelten auch für Datenbankschlüssel als schlecht (16-Byte-Guid vs. 4-Byte-Ganzzahl). Bei großen Datenmengen verlangsamen Guids die Suche.

Hase
quelle
Nicht immer - inkrementelle GUIDs sind möglich. Die Indizes werden immer noch größer sein, aber die Nachschlagstrafe wird nicht annähernd so schlimm sein.
Sam
6
Eigentlich geht es ihnen gut. Sie müssen die Beziehung zwischen der E / A-Zeit des Zeitdatenträgers und dem Vergleich der Werte im Speicher untersuchen. Da Festplattenzugriffszeiten den Speichervergleich überfordern, ist IO das einzige, was bei der Analyse der Datenbankleistung wirklich wichtig ist. Ob der Schlüssel eine GUID, eine Zeichenfolge oder eine Ganzzahl ist, ist nicht wirklich kritisch. Die Indexgröße beeinflusst, wie viele Indexwerte auf eine Seite passen. Es spielt jedoch keine Rolle, ob der Schlüssel ein 4-Byte-Int (der möglicherweise nicht groß genug ist und nicht vom Client generiert werden kann) oder ein 16-Byte-Wert ist. In einigen Datenbanken können die rowId 16 Byte groß sein.
Ipaul
9

Es gibt ein weiteres Problem bei der Verwendung von Zeichenfolgen als Schlüssel oder genauer gesagt bei der Verwendung von Zeichenfolgenliteralen als Schlüssel, wobei reine Leistungs- / Effizienzgründe außer Acht gelassen werden. Tippfehler. Wenn Sie Zeichenfolgenliterale als Schlüssel in einem Wörterbuch verwenden, können Sie sich auf eine böse Überraschung einstellen, wenn einer "ReceiverId"zu einem wird "RecieverId". Richten Sie Konstanten ein, um die Schlüsselwerte zu speichern und sie bei jedem Zugriff auf das Wörterbuch wiederzuverwenden.

Sie können sagen, dass eine erstaunliche Anzahl von .NET-Codebeispielen im Web String-Literale verwendet, die diese zweifelhafte Praxis verbreiten. ASP.NET mit all den Sitzungen, ViewStates und QueryParams, die über die Codebasis verstreut sind, ist hier besonders schuldig.

scrwtp
quelle
IMHO nicht trivial. Ich habe auch Fälle gesehen, in denen es Schlüssel "1"und "1 "in der gleichen Tabelle gibt.
pswg
Noch amüsanter wird es, wenn Sie auch die Groß- und Kleinschreibung berücksichtigen. Gesehene Unmengen von Menschen, einschließlich mir, stolpern direkt in diese.
Tony Hopkinson
Noch besser als die Verwendung von Konstanten, zumindest in C #, ist die Verwendung von Ausdrücken. Auf diese Weise können Sie Ihre Zeichenfolgen aus den Namen von Methoden / Eigenschaften usw. generieren, sodass Ihre Zeichenfolgensuchen typsicher und refaktorfreundlich werden.
GoatInTheMachine
4

Hier gibt es viele Kompromisse. Eigentlich verwende ich häufig String-Schlüssel, aber oft füge ich Ersatz-Sekundärschlüssel für Joins hinzu (offensichtlich wäre es umgekehrt, wenn ich MySQL verwenden würde). Es gibt Fälle, in denen ich es jedoch nicht tue.

Zunächst bin ich ein Fan von natürlichen Schlüsseln als Primärschlüssel, mit denen die Datenbank gut umgehen kann (zum Beispiel PostgreSQL). Dies hilft bei der Normalisierung und sorgt für ein klareres Datenbankdesign. Ersatzschlüssel erleichtern das Beitreten.

Es gibt zwei Gründe, warum ich normalerweise Ersatzschlüssel hinzufüge:

  1. Es ist nicht immer klar, was ein natürlicher Schlüssel ist. Manchmal müssen diese geändert werden. Das Ändern eines natürlichen, zusammengesetzten Schlüssels, wenn er für Verknüpfungen und referenzielle Integrität verwendet wird, ist kompliziert und fehleranfällig.

  2. Die Verbindungsleistung bei zusammengesetzten Schlüsseln ist problematisch, und wenn Sie sich erst einmal auf dem natürlichen Schlüsselweg befinden, bleiben Sie dort stecken.

In Fällen, in denen ein natürlicher Schlüssel eine Definition, eine einzelne Spalte und ein Text ist, füge ich normalerweise den Zeichenfolgenschlüssel hinzu. Mein Grund dafür ist, dass dies häufig vermeidet, beim Nachschlagen mitzumachen. Die häufigste Verwendung ist die Bereitstellung eines geeigneten Datenbankentwurfs für den Anwendungsfall von Aufzählungstypen. In den meisten Fällen ist für Routineabfragen kein zusätzlicher Join erforderlich. Wo dies der Fall ist, sind String-Schlüssel als Join-Schlüssel absolut sinnvoll.

Beispielsweise speichern wir in LedgerSMB Konto-Kategorisierungen. Diese werden durch eine Zeichenfolgenreferenz identifiziert. Einige andere Daten werden mit der Zeichenfolgenreferenz gespeichert, die zur Durchsetzung von Regeln in Bezug auf die Kombinationen von Kategorisierungen verwendet wird, die sich auf ein Konto auswirken können. Die einzige Zeit, in der Logik benötigt wird, ist das Speichern einer Reihe von Kategorisierungen, sodass wir uns dem Zeichenfolgenschlüssel anschließen.

Ich glaube nicht, dass es nur um die Indexgröße geht, warum die Standardeinstellung Ganzzahlschlüssel ist. Ein großes Problem ist die Verwaltung von Schlüsseln. Da der Schlüssel willkürlich ist und Sie möglicherweise mit Millionen von Datensätzen zu tun haben, müssen Sie die Möglichkeit haben, eindeutige Zeichenfolgen zu generieren. Es gibt Fälle, in denen Benutzer UUIDs verwenden, die Wahrscheinlichkeit einer UUID-Kollision jedoch ungleich Null ist. Wenn Milliarden von Datensätzen gespeichert sind, ist diese Wahrscheinlichkeit so hoch, dass sie tatsächlich angezeigt wird, während die Wahrscheinlichkeit einer Kollision mit inkrementierten Ganzzahltypen Null beträgt per Definition.

Chris Travers
quelle
Es ist nicht ungleich Null, wenn Sie es schaffen, den ganzzahligen Typ wieder auf Null zu setzen. Für einen vorzeichenlosen 32-Bit-Typ ist das nur 4G entfernt, was mit „Milliarden von Datensätzen“ beunruhigend ist…
Donal Fellows
Wenn Sie eine Datenbank haben, die "error anstatt wrap around" anzeigt, ist sie null. In jedem Fall ist es einfacher, die Möglichkeit einer Kollision mit inkrementierenden ganzen Zahlen als mit Pseudozufallswerten zu handhaben.
Chris Travers
1

Es gibt eine Reihe potenzieller Probleme bei der Verwendung von Zeichenfolgen als Schlüssel, insbesondere bei SQL-ähnlichen Tabellen. Wie von @bunny erwähnt, werden die Indizes für Ihre Tabellen größer sein, aber ich denke, dass Fremdschlüsselbeziehungen zur Tabelle BEIDE Tabellen enthalten, die die Zeichenfolge enthalten, im Gegensatz zu einer leichteren (Ganzzahl-) Kennung . Wenn Sie feststellen, dass es noch mehr Tabellen mit Verweisen auf die erste gibt, werden die Zeichenfolgenschlüssel in Ihrer gesamten Datenbank verbreitet.

Matthew Flynn
quelle
1

Es ist an und für sich keine schlechte Idee, im Nachhinein ist es normalerweise ein schlechter Designkompromiss. Die Flexibilität und Bandbreite der Saiten im Vergleich zu den zusätzlichen Kosten und der Komplexität.

Wenn der Jobbereich ganzzahlig ist und der Großteil der teuren Verarbeitung nicht wissen muss, was die Ganzzahl darstellt, verwenden Sie eine.

Tony Hopkinson
quelle
0

Sie haben irgendwie die falschen Daten aus einer Hashtabelle abgerufen.

Meinten Sie "DaytimeTelephone" oder "EveningTelephone"?

oder

Meinten Sie 1234567 oder 1234576?

Während Zahlen für die Maschine wahrscheinlich effizienter sind , liegt es an Ihnen und mir , zu verstehen, was passiert ist, und zu diesem Zeitpunkt ein paar Bytes an Speicherplatz zu sparen ein paar Mikro (nano?) - Sekunden der Verarbeitung verliert aus Klarheit jedes einzelne Mal.

Phill W.
quelle
1
Und so erhalten Sie eine Liste von Konstanten, in der der Name der Konstanten in Ihrem Code die magische Zahl darstellt ... Java-Aufzählungen helfen, diese noch weiter zu abstrahieren und Sie nur mit dem Namen und der Ordnungszahl zu belassen Mapping unsichtbar.
4.
-1

Viele Kompromisse und keine richtige Antwort. Viele Programmierer würden niemals in Betracht ziehen, Zeichenfolgenschlüssel in der Datenbank zu verwenden, da sie sich nicht mit Hashing und der Funktionsweise einer Datenbank auskennen. Saitentasten sind unter vielen Umständen eine gute Wahl, wenn sie extrem stabil oder bedeutungslos sind (Ersatztasten).

moss23
quelle
2
Diese Antwort fügt nichts hinzu, was noch nicht in den anderen Antworten gesagt wurde.
Martijn Pieters
-2

string key ist sinnvoll, wenn es um Nachschlagetabellen mit etwa 10-100 kurzen Zeichenfolgendatensätzen geht. zugehörige Daten sind besser lesbar + zB Änderungsverfolgung (numerische ID / Guid-ID vs. Zeichenfolge, zB "Administrator"); Übrigens verwendet die ASP.NET-Mitgliedschaftsdatenbank Zeichenfolgenschlüssel für AspNetRoles.

Alfred Hitchcock
quelle