Diese Frage dreht sich darum, wie ich eine Datenbank entwerfen soll, es kann sich um relationale / nosql-Datenbanken handeln, je nachdem, welche die bessere Lösung sein wird
Unter der Voraussetzung, dass Sie ein System erstellen müssen, das eine Datenbank zur Verfolgung von "Unternehmen" und "Benutzer" umfasst. Ein einzelner Benutzer gehört immer nur einer Firma an
- Ein Benutzer kann nur einer Firma angehören
- Ein Unternehmen kann viele Benutzer haben
Das Design für den "Company" -Tisch ist recht unkompliziert. Firma wird die folgenden Attribute / Spalten haben: (Lassen Sie es uns einfach halten)
ID, COMPANY_NAME, CREATED_ON
Erstes Szenario
Einfach und unkompliziert, Benutzer haben alle das gleiche Attribut. Dies kann also einfach in relationaler Art und Weise durchgeführt werden. Benutzertabelle:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CREATED_ON
Zweites Szenario
Was passiert, wenn verschiedene Unternehmen unterschiedliche Profilattribute für ihren Benutzer speichern möchten? Jedes Unternehmen verfügt über definierte Attribute, die für alle Benutzer dieses Unternehmens gelten.
Beispielsweise:
- Firma A möchte speichern: LIKE_MOVIE (boolean), LIKE_MUSIC (boolean)
- Firma B möchte speichern: FAV_CUISINE (String)
- Firma C möchte speichern: OWN_DOG (boolean), DOG_COUNT (int)
Ansatz 1
Die Brute-Force-Methode besteht darin, ein einziges Schema für den Benutzer zu haben und Nullen zuzulassen, wenn sie nicht zur Firma gehören:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, LIKE_MOVIE, LIKE_MUSIC, FAV_CUISINE, OWN_DOG, DOG_COUNT, CREATED_ON
Das ist ein bisschen böse, weil Sie am Ende viele NULL-Werte und Benutzerzeilen haben, deren Spalten für sie irrelevant sind (dh, alle Benutzer, die zu Unternehmen A gehören, haben NULL-Werte für FAV_CUISINE, OWN_DOG, DOG_COUNT).
Ansatz 2
Ein zweiter Ansatz ist, ein "Freiformfeld" zu haben:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_1, CUSTOM_2, CUSTOM_3, CREATED_ON
Was für sich genommen unangenehm wäre, da Sie keine Ahnung haben, was benutzerdefinierte Felder sind, spiegelt der Datentyp nicht die gespeicherten Werte wider (z. B. speichern wir den Wert int als VARCHAR).
Ansatz 3
Ich habe mir das PostgreSQL-JSON-Feld angesehen. In diesem Fall haben Sie:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_PROFILE_JSON, CREATED_ON
Wie können Sie in diesem Fall verschiedene Schemas auf einen Benutzer anwenden? Ein Benutzer mit Firma A hat ein Schema, das so aussieht
{"LIKE_MOVIE":"boolean", "LIKE_MUSIC": "boolean"}
Während ein Benutzer mit Firma C ein anderes Schema hat:
{"OWN_DOG ":"boolean", "DOG_COUNT": "int"}
Wie soll ich dieses Problem lösen? Wie kann ich die Datenbank richtig entwerfen, um dieses flexible Schema für ein einzelnes "Objekt" (Benutzer) basierend auf der Beziehung, die sie haben (Firma), zu ermöglichen?
relationale Lösung? nosql lösung?
Bearbeiten: Ich habe auch über eine "CUSTOM_PROFILE" -Tabelle nachgedacht, in der Benutzerattribute im Wesentlichen in Zeilen und nicht in Spalten gespeichert werden.
Bei diesem Ansatz gibt es zwei Probleme:
1) Die Datenmenge pro Benutzer wächst eher als Zeilen als als als Spalten. Dies bedeutet, dass für ein vollständiges Bild des Benutzers eine Vielzahl von Verknüpfungen durchgeführt werden muss und mehrere Verknüpfungen mit der Tabelle "Benutzerdefiniertes Profil" für die verschiedenen benutzerdefinierten Attribute erforderlich sind
2) Der Datenwert wird immer als VARCHAR gespeichert, um generisch zu sein, auch wenn wir wissen, dass die Daten ganzzahlig oder boolesch usw. Sein sollen
quelle
Antworten:
Bitte betrachten Sie dies als Alternative. In den beiden vorherigen Beispielen müssen Sie Änderungen am Schema vornehmen, da der Anwendungsbereich wächst. Außerdem ist es schwierig, die Lösung "custom_column" zu erweitern und zu verwalten. Schließlich haben Sie Custom_510 und stellen sich vor, wie schrecklich diese Tabelle sein wird, mit der Sie arbeiten können.
Lassen Sie uns zuerst Ihr Firmenschema verwenden.
Als Nächstes verwenden wir Ihr Benutzerschema auch für die erforderlichen Attribute der obersten Ebene, die von allen Unternehmen verwendet bzw. gemeinsam genutzt werden.
Als Nächstes erstellen wir eine Tabelle, in der wir unsere dynamischen Attribute definieren, die für die benutzerdefinierten Benutzerattribute der einzelnen Unternehmen spezifisch sind. Ein Beispielwert für die Attributspalte wäre "LikeMusic":
Als Nächstes definieren wir eine UserAttributes-Tabelle, die Benutzerattributwerte enthält
Dies kann auf viele Arten geändert werden, um die Leistung zu verbessern. Sie können mehrere Tabellen für UserAttributes verwenden, wobei jede für den in Value gespeicherten Datentyp spezifisch ist, oder Sie lassen sie einfach als VarChar und arbeiten mit ihr als Schlüsselwertspeicher.
Möglicherweise möchten Sie auch CompanyId aus der UserAttributeDefiniton-Tabelle in eine Querverweistabelle verschieben, um eine spätere Überprüfung durchzuführen.
quelle
Verwenden Sie eine NoSQL-Datenbank. Es würde Firmen- und Benutzerdokumente geben. Die Benutzer würden einen Teil ihres Schemas basierend auf einer Benutzervorlage dynamisch erstellen lassen (Text zur Angabe von Feldern / Typen für diese Firma).
So könnte es in so etwas wie Firebase.com aussehen. Sie müssten lernen, wie man es in einem beliebigen Programm macht.
quelle
Wenn Sie häufig mit benutzerdefinierten Feldanforderungen konfrontiert werden, modelliere ich diese ziemlich ähnlich wie die Datenbank. Erstellen Sie eine Tabelle mit den Metadaten zu jedem benutzerdefinierten Feld, CompanyCustomField (zu wem es gehört, dem Datentyp usw.) und einer weiteren Tabelle CompanyCustomFieldValues, die die CustomerId, FieldId und den Wert enthält. Wenn Sie so etwas wie Microsoft SQL Server verwenden, müsste die Wertespalte ein sql_variant-Datentyp sein.
Dies ist natürlich nicht einfach, da Sie eine Schnittstelle benötigen, über die Administratoren benutzerdefinierte Felder für jeden Kunden definieren können, und eine weitere Schnittstelle, die diese Metadaten verwendet, um eine Benutzeroberfläche zum Erfassen der Feldwerte zu erstellen. Und wenn Sie andere Anforderungen haben, z. B. das Gruppieren von Feldern oder das Erstellen einer Auswahlliste, müssen Sie dies mit mehr Metadaten / anderen Tabellen (z. B. CompanyCustomFieldPickListOptions) abgleichen.
Dies ist nicht trivial, hat aber den Vorteil, dass keine Datenbankänderungen / Codeänderungen für jedes neue benutzerdefinierte Feld erforderlich sind. Alle anderen Funktionen von benutzerdefinierten Feldern müssen ebenfalls codiert werden (z. B. wenn Sie einen Zeichenfolgenwert durch einen regulären Ausdruck überprüfen möchten oder nur Datumsangaben zwischen bestimmten Bereichen zulassen möchten oder wenn Sie ein benutzerdefiniertes Feld basierend auf einem anderen benutzerdefinierten Feldwert aktivieren müssen ).
quelle
Eine Alternative zu den anderen Antworten besteht darin, eine Tabelle namens profile_attrib oder eine ähnliche Tabelle zu haben, die das Schema vollständig von Ihrer Anwendung verwaltet.
Wenn benutzerdefinierte Attribute hinzugefügt werden,
ALTER TABLE profile_attrib ADD COLUMN like_movie TINYINT(1)
können Sie das Löschen verhindern. Dies würde Ihren Beitritt minimieren und dennoch Flexibilität bieten.Ich vermute, der Nachteil ist, dass die Anwendung jetzt die Berechtigung zum Ändern von Tabellen für die Datenbank benötigt, und Sie müssen gescheit sein, die Spaltennamen zu bereinigen.
quelle
[^\w-]+
sollte es ziemlich gut machen und nichts0-9A-Za-z_-
zulassen, was nicht ist - aber ja, Desinfektion ist hier ein Muss, um vor Böswilligkeit oder Dummheit zu schützen.Ihre Frage hat viele mögliche Lösungen. Eine Lösung besteht darin, die zusätzlichen Attribute als XML zu speichern. Das XML kann als Text gespeichert werden oder wenn Sie eine Datenbank verwenden, die XML-Typen als XML unterstützt (SQL Server). Das Speichern als Text schränkt Ihre Abfragemöglichkeit ein (wie das Suchen nach einem benutzerdefinierten Attribut), aber wenn Sie nur speichern und abrufen müssen, ist dies eine gute Lösung. Wenn eine Abfrage erforderlich ist, ist das Speichern der XML-Datei als XML-Typ eine bessere Option (obwohl dies herstellerspezifischer ist).
Dies gibt einem die Möglichkeit, eine beliebige Anzahl von Attributen für einen Kunden zu speichern, indem lediglich eine zusätzliche Spalte in der Kundentabelle hinzugefügt wird. Man könnte die Attribute als Hashset oder Wörterbuch speichern, man verliert die Typensicherheit, da alles eine Zeichenfolge ist, aber wenn man eine Standardformatzeichenfolge für Datumsangaben, Zahlen und Boolesche Werte erzwingt, funktioniert dies in Ordnung.
Für mehr Informationen:
https://msdn.microsoft.com/en-us/library/hh403385.aspx
@ WalterMittys Antwort ist ebenfalls gültig. Wenn man jedoch viele Kunden mit unterschiedlichen Attributen hat, könnte man nach dem Vererbungsmodell viele Tabellen erhalten. Dies hängt davon ab, wie viele benutzerdefinierte Attribute von Kunden gemeinsam genutzt werden.
quelle
Sie sollten Ihre Datenbank so normalisieren, dass Sie für jede Art von Unternehmensprofil 3 verschiedene Tabellen haben. In Ihrem Beispiel hätten Sie Tabellen mit Spalten:
Bei diesem Ansatz wird davon ausgegangen, dass Sie die Form der Informationen kennen, die ein Unternehmen speichern möchte, und dass sie sich nicht häufig ändern. Wenn die Form der Daten zur Entwurfszeit unbekannt ist, ist es wahrscheinlich besser, dieses JSON-Feld oder eine nosql-Datenbank zu verwenden.
quelle
Aus dem einen oder anderen Grund sind Datenbanken das Feld, in dem der Effekt der inneren Plattform am häufigsten auftritt. Dies ist nur ein weiterer Fall des Auftauchens des Anti-Patterns.
In diesem Fall versuchen Sie, die natürliche und korrekte Lösung zu finden. Die Benutzer von Unternehmen A sind keine Benutzer von Unternehmen B, und sie sollten ihre eigenen Tabellen für ihre eigenen Felder haben.
Ihr Datenbankanbieter stellt Ihnen keine Gebühren für die Tabelle in Rechnung, und Sie benötigen nicht den doppelten Speicherplatz für die doppelten Tabellen (zwei Tabellen sind in der Tat effizienter, da Sie die Attribute von A nicht für die Benutzer von B speichern. Auch wenn Sie nur NULL-Werte speichern braucht Platz).
Wenn genügend gemeinsame Felder vorhanden sind, können Sie diese natürlich in eine gemeinsam genutzte Benutzertabelle einbeziehen und in jeder der firmenspezifischen Benutzertabellen einen Fremdschlüssel haben. Dies ist eine so einfache Struktur, dass kein Datenbankabfrageoptimierer damit zu kämpfen hat. Jeder notwendige JOIN ist trivial.
quelle
Meine Lösung geht davon aus, dass Sie diese Abfrage von einem Programm aus aufrufen und die Nachbearbeitung durchführen können. Sie können folgende Spalten haben:
CUSTOM_VALUES ist vom Typ string, der das Schlüssel- und Wertepaar speichert. Schlüssel wird Spaltenname sein und Wert wird Spaltenwert sein, z
In diesem CUSTOM_VALUES werden nur die vorhandenen Informationen gespeichert. Wenn Sie vom Programm abfragen, können Sie diesen String teilen und verwenden.
Ich habe diese Logik verwendet und sie funktioniert einwandfrei. Sie müssen lediglich die Filterlogik im Code und nicht in der Abfrage anwenden.
quelle