Ich implementiere das folgende Modell zum Speichern benutzerbezogener Daten in meiner Tabelle - ich habe 2 Spalten - uid
(Primärschlüssel) und eine meta
Spalte, in der andere Daten über den Benutzer im JSON-Format gespeichert werden.
uid | meta
--------------------------------------------------
1 | {name:['foo'],
| emailid:['[email protected]','[email protected]']}
--------------------------------------------------
2 | {name:['sann'],
| emailid:['[email protected]','[email protected]']}
--------------------------------------------------
Ist dies ein besserer Weg (Performance-weise, Design-weise) als das Ein-Spalt-per-Eigenschaft - Modell, in dem die Tabelle wie viele Spalten hat uid
, name
, emailid
.
Was mir am ersten Modell gefällt, ist, dass Sie so viele Felder wie möglich hinzufügen können, ohne Einschränkungen.
Außerdem habe ich mich gefragt, nachdem ich das erste Modell implementiert habe. Wie führe ich eine Abfrage durch, z. B. möchte ich alle Benutzer abrufen, die einen Namen wie "foo" haben?
Frage - Was ist der bessere Weg, um benutzerbezogene Daten (unter Berücksichtigung der Tatsache, dass die Anzahl der Felder nicht festgelegt ist) mit - JSON oder Spalte pro Feld in der Datenbank zu speichern? Wenn das erste Modell implementiert ist, wie kann die Datenbank wie oben beschrieben abgefragt werden? Sollte ich beide Modelle verwenden, indem ich alle Daten, die von einer Abfrage durchsucht werden können, in einer separaten Zeile und die anderen Daten in JSON speichere (ist eine andere Zeile)?
Aktualisieren
Ist es ratsam, beide Modelle zu verwenden, da es nicht zu viele Spalten gibt, in denen ich suchen muss? Schlüssel pro Spalte für die Daten, die ich suchen muss, und JSON für andere (in derselben MySQL-Datenbank)?
quelle
Antworten:
Aktualisiert am 4. Juni 2017
Angesichts der Tatsache, dass diese Frage / Antwort an Popularität gewonnen hat, dachte ich, dass es ein Update wert ist.
Als diese Frage ursprünglich gestellt wurde, hatte MySQL keine Unterstützung für JSON-Datentypen und die Unterstützung in PostgreSQL steckte noch in den Kinderschuhen. Seit 5.7 unterstützt MySQL jetzt einen JSON-Datentyp (in einem binären Speicherformat), und PostgreSQL JSONB ist erheblich ausgereift. Beide Produkte bieten performante JSON-Typen, in denen beliebige Dokumente gespeichert werden können, einschließlich der Unterstützung für die Indizierung bestimmter Schlüssel des JSON-Objekts.
Ich stehe jedoch weiterhin zu meiner ursprünglichen Aussage, dass Ihre Standardeinstellung bei Verwendung einer relationalen Datenbank weiterhin Spalte pro Wert sein sollte. Relationale Datenbanken basieren immer noch auf der Annahme, dass die darin enthaltenen Daten ziemlich gut normalisiert sind. Der Abfrageplaner verfügt über bessere Optimierungsinformationen beim Betrachten von Spalten als beim Betrachten von Schlüsseln in einem JSON-Dokument. Fremdschlüssel können zwischen Spalten erstellt werden (jedoch nicht zwischen Schlüsseln in JSON-Dokumenten). Wichtig: Wenn der Großteil Ihres Schemas volatil genug ist, um die Verwendung von JSON zu rechtfertigen, sollten Sie zumindest überlegen, ob eine relationale Datenbank die richtige Wahl ist.
Allerdings sind nur wenige Anwendungen perfekt relational oder dokumentenorientiert. Die meisten Anwendungen haben eine Mischung aus beiden. Hier sind einige Beispiele, bei denen ich JSON persönlich in einer relationalen Datenbank als nützlich empfunden habe:
Beim Speichern von E-Mail-Adressen und Telefonnummern für einen Kontakt ist das Speichern als Werte in einem JSON-Array viel einfacher als das Verwalten mehrerer separater Tabellen
Speichern beliebiger Benutzereinstellungen für Schlüssel / Werte (wobei der Wert boolesch, textuell oder numerisch sein kann und Sie keine separaten Spalten für verschiedene Datentypen haben möchten)
Speichern von Konfigurationsdaten ohne definiertes Schema (wenn Sie Zapier oder IFTTT erstellen und Konfigurationsdaten für jede Integration speichern müssen)
Ich bin mir sicher, dass es auch andere gibt, aber dies sind nur einige kurze Beispiele.
Ursprüngliche Antwort
Wenn Sie wirklich so viele Felder hinzufügen möchten, wie Sie möchten, ohne Einschränkung (außer einer willkürlichen Beschränkung der Dokumentgröße), sollten Sie eine NoSQL-Lösung wie MongoDB in Betracht ziehen.
Für relationale Datenbanken: Verwenden Sie eine Spalte pro Wert. Das Einfügen eines JSON-Blobs in eine Spalte macht das Abfragen praktisch unmöglich (und schmerzhaft langsam, wenn Sie tatsächlich eine Abfrage finden, die funktioniert).
Relationale Datenbanken nutzen bei der Indizierung Datentypen und sollen mit einer normalisierten Struktur implementiert werden.
Als Randnotiz: Dies bedeutet nicht, dass Sie JSON niemals in einer relationalen Datenbank speichern sollten. Wenn Sie echte Metadaten hinzufügen oder wenn Ihr JSON Informationen beschreibt, die nicht abgefragt werden müssen und nur zur Anzeige verwendet werden, ist es möglicherweise übertrieben, eine separate Spalte für alle Datenpunkte zu erstellen.
quelle
virtually impossible to query
" - heute psql ermöglicht es Ihnen, seine jsonb"For relational databases"
in Ihrer Antwort = PWie die meisten Dinge "kommt es darauf an". Es ist an und für sich nicht richtig oder falsch / gut oder schlecht, Daten in Spalten oder JSON zu speichern. Es hängt davon ab, was Sie später damit machen müssen. Wie werden Sie voraussichtlich auf diese Daten zugreifen? Müssen Sie auf andere Daten verweisen?
Andere Leute haben ziemlich gut geantwortet, was der technische Kompromiss ist.
Nicht viele Leute haben darüber gesprochen, dass sich Ihre App und Funktionen im Laufe der Zeit weiterentwickeln und wie sich diese Datenspeicherungsentscheidung auf Ihr Team auswirkt.
Da eine der Versuchungen bei der Verwendung von JSON darin besteht, die Migration von Schemata zu vermeiden. Wenn das Team nicht diszipliniert ist, ist es sehr einfach, ein weiteres Schlüssel / Wert-Paar in ein JSON-Feld einzufügen. Es gibt keine Migration dafür, niemand erinnert sich, wofür es ist. Es gibt keine Validierung.
Mein Team verwendete JSON neben traditionellen Säulen in Postgres und zuerst war es das Beste seit geschnittenem Brot. JSON war attraktiv und leistungsstark, bis wir eines Tages feststellten, dass Flexibilität mit Kosten verbunden war und plötzlich ein echtes Problem darstellt. Manchmal schleicht sich dieser Punkt sehr schnell ein und dann wird es schwierig, ihn zu ändern, weil wir so viele andere Dinge auf dieser Entwurfsentscheidung aufgebaut haben.
Überstunden, das Hinzufügen neuer Funktionen und das Vorhandensein der Daten in JSON führten zu komplizierteren Abfragen als die, die hinzugefügt worden wären, wenn wir uns an herkömmliche Spalten gehalten hätten. Also fingen wir an, bestimmte Schlüsselwerte wieder in Spalten zu fischen, damit wir Verknüpfungen herstellen und Vergleiche zwischen Werten anstellen konnten. Schlechte Idee. Jetzt hatten wir Duplikate. Ein neuer Entwickler würde an Bord kommen und verwirrt sein? In welchen Wert sollte ich zurücksparen? Der JSON oder die Spalte?
Die JSON-Felder wurden zu Müllschubladen für kleine Stücke von diesem und jenem. Keine Datenvalidierung auf Datenbankebene, keine Konsistenz oder Integrität zwischen Dokumenten. Das hat all diese Verantwortung in die App übertragen, anstatt eine harte Typprüfung und Einschränkungsprüfung aus herkömmlichen Spalten zu erhalten.
Rückblickend erlaubte uns JSON, sehr schnell zu iterieren und etwas aus der Tür zu holen. Es war toll. Nachdem wir jedoch eine bestimmte Teamgröße erreicht hatten, konnten wir uns aufgrund der Flexibilität auch mit einem langen Seil technischer Schulden aufhängen, was den späteren Fortschritt der Feature-Entwicklung verlangsamte. Mit Vorsicht verwenden.
Überlegen Sie lange und gründlich, wie Ihre Daten aussehen. Es ist das Fundament Ihrer App. Wie werden die Daten im Laufe der Zeit verwendet? Und wie ist es wahrscheinlich zu ändern?
quelle
Wirf es einfach raus, aber WordPress hat eine Struktur für diese Art von Sachen (zumindest war WordPress der erste Ort, an dem ich es beobachtet habe, es hat wahrscheinlich seinen Ursprung woanders).
Es erlaubt unbegrenzte Schlüssel und ist schneller zu suchen als ein JSON-Blob, aber nicht so schnell wie einige der NoSQL-Lösungen.
BEARBEITEN
Zum Speichern von Verlauf / mehreren Schlüsseln
und über so etwas abfragen:
quelle
emailid
Schlüssel in dem Beispiel, das ich in meiner Frage gegeben habe.Der Nachteil des Ansatzes ist genau das, was Sie erwähnt haben:
es macht es SEHR langsam, Dinge zu finden, da Sie jedes Mal eine Textsuche durchführen müssen.
Der Wert pro Spalte entspricht stattdessen der gesamten Zeichenfolge.
Ihr Ansatz (JSON-basierte Daten) eignet sich für Daten, nach denen Sie nicht suchen müssen und die nur zusammen mit Ihren normalen Daten angezeigt werden müssen.
Bearbeiten: Zur Verdeutlichung gilt das oben Gesagte für klassische relationale Datenbanken. NoSQL verwendet JSON intern und ist wahrscheinlich eine bessere Option, wenn dies das gewünschte Verhalten ist.
quelle
Grundsätzlich wird das erste Modell, das Sie verwenden, als dokumentbasierter Speicher bezeichnet. Sie sollten sich die beliebte dokumentbasierte NoSQL-Datenbank wie MongoDB und CouchDB ansehen . Grundsätzlich speichern Sie in dokumentbasierten Datenbanken Daten in JSON-Dateien und können diese JSON-Dateien abfragen.
Das zweite Modell ist die beliebte relationale Datenbankstruktur.
Wenn Sie eine relationale Datenbank wie MySQL verwenden möchten, würde ich Ihnen empfehlen, nur das zweite Modell zu verwenden. Es macht keinen Sinn, MySQL zu verwenden und Daten wie im ersten Modell zu speichern .
Um Ihre zweite Frage zu beantworten, gibt es keine Möglichkeit, Namen wie 'foo' abzufragen, wenn Sie das erste Modell verwenden .
quelle
Es scheint, dass Sie hauptsächlich zögern, ein relationales Modell zu verwenden oder nicht.
So wie es aussieht, würde Ihr Beispiel ziemlich gut zu einem relationalen Modell passen, aber das Problem kann natürlich auftreten, wenn Sie dieses Modell weiterentwickeln müssen.
Wenn Sie nur eine (oder einige vordefinierte) Attributebenen für Ihre Hauptentität (Benutzer) haben, können Sie weiterhin ein EAV-Modell (Entity Attribute Value) in einer relationalen Datenbank verwenden. (Dies hat auch Vor- und Nachteile.)
Wenn Sie davon ausgehen, dass Sie weniger strukturierte Werte erhalten, nach denen Sie mit Ihrer Anwendung suchen möchten, ist MySQL hier möglicherweise nicht die beste Wahl.
Wenn Sie PostgreSQL verwenden, können Sie möglicherweise das Beste aus beiden Welten herausholen. (Dies hängt wirklich von der tatsächlichen Struktur der Daten hier ab ... MySQL ist auch nicht unbedingt die falsche Wahl, und die NoSQL-Optionen können von Interesse sein. Ich schlage nur Alternativen vor.)
In der Tat kann PostgreSQL einen Index für (unveränderliche) Funktionen erstellen (was MySQL meines Wissens nicht kann), und in neueren Versionen können Sie PLV8 für die JSON-Daten direkt verwenden , um Indizes für bestimmte interessierende JSON-Elemente zu erstellen, was sich verbessern würde die Geschwindigkeit Ihrer Abfragen bei der Suche nach diesen Daten.
BEARBEITEN:
Das Mischen der beiden Modelle ist nicht unbedingt falsch (vorausgesetzt, der zusätzliche Speicherplatz ist vernachlässigbar), kann jedoch zu Problemen führen, wenn Sie nicht sicherstellen, dass die beiden Datensätze synchron bleiben: Ihre Anwendung darf niemals einen ändern, ohne auch den anderen zu aktualisieren .
Eine gute Möglichkeit, dies zu erreichen, besteht darin, dass ein Trigger die automatische Aktualisierung durchführt, indem er bei jeder Aktualisierung oder Einfügung eine gespeicherte Prozedur auf dem Datenbankserver ausführt. Soweit mir bekannt ist, wird die Sprache der gespeicherten MySQL-Prozeduren wahrscheinlich nicht für jede Art von JSON-Verarbeitung unterstützt. Auch hier sollte PostgreSQL mit PLV8-Unterstützung (und möglicherweise andere RDBMS mit flexibleren Sprachen für gespeicherte Prozeduren) nützlicher sein (das automatische Aktualisieren Ihrer relationalen Spalte mithilfe eines Triggers ähnelt dem Aktualisieren eines Index auf dieselbe Weise).
quelle
Einige Zeit Joins auf dem Tisch sind ein Overhead. Sagen wir für OLAP. Wenn ich zwei Tabellen habe, ist eine ORDERS-Tabelle und eine ORDER_DETAILS. Um alle Bestelldetails zu erhalten, müssen wir zwei Tabellen verbinden. Dadurch wird die Abfrage langsamer, wenn keine der Zeilen in den Tabellen zunimmt, beispielsweise in Millionen. Die Links- / Rechts-Verknüpfung ist zu langsam als die innere Verknüpfung. Ich denke, wenn wir JSON-Zeichenfolge / Objekt in den jeweiligen ORDERS-Eintrag hinzufügen, wird JOIN vermieden. Das Hinzufügen von Berichten wird schneller sein ...
quelle
kurze Antwort Sie müssen zwischen ihnen mischen, verwenden Sie json für Daten, mit denen Sie keine Beziehung herstellen möchten, wie Kontaktdaten, Adresse, Produktvariablen
quelle
Sie versuchen, ein nicht relationales Modell in eine relationale Datenbank einzubauen . Ich denke, Sie sollten eine NoSQL-Datenbank wie MongoDB besser verwenden . Es gibt kein vordefiniertes Schema, das Ihrer Anforderung entspricht, die Anzahl der Felder nicht zu beschränken (siehe das typische Beispiel für eine MongoDB-Sammlung). Lesen Sie die MongoDB- Dokumentation , um eine Vorstellung davon zu erhalten, wie Sie Ihre Dokumente abfragen würden, z
quelle
Wie andere bereits betont haben, werden Abfragen langsamer sein. Ich würde vorschlagen, stattdessen mindestens eine '_ID'-Spalte hinzuzufügen, um danach abzufragen.
quelle