Wie entwerfe ich eine Datenbank für benutzerdefinierte Felder?


145

Meine Anforderungen sind:

  • Muss in der Lage sein, benutzerdefinierte Felder eines beliebigen Datentyps dynamisch hinzuzufügen
  • Muss in der Lage sein, UDFs schnell abzufragen
  • Sie müssen in der Lage sein, Berechnungen für UDFs basierend auf dem Datentyp durchzuführen
  • Muss in der Lage sein, UDFs nach Datentyp zu sortieren

Andere Informationen:

  • Ich suche hauptsächlich Leistung
  • Es gibt einige Millionen Stammsätze, an die UDF-Daten angehängt werden können
  • Bei meiner letzten Überprüfung befanden sich in unserer aktuellen Datenbank über 50 Mio. UDF-Datensätze
  • Meistens ist eine UDF nur an einige Tausend der Stammdatensätze angehängt, nicht an alle
  • UDFs werden nicht verbunden oder als Schlüssel verwendet. Es handelt sich lediglich um Daten, die für Abfragen oder Berichte verwendet werden

Optionen:

  1. Erstellen Sie eine große Tabelle mit StringValue1, StringValue2 ... IntValue1, IntValue2 usw. Ich hasse diese Idee, werde sie aber in Betracht ziehen, wenn mir jemand sagen kann, dass sie besser ist als andere Ideen und warum.

  2. Erstellen Sie eine dynamische Tabelle, die bei Bedarf eine neue Spalte hinzufügt. Diese Idee gefällt mir auch nicht, da ich der Meinung bin, dass die Leistung langsam ist, wenn Sie nicht jede Spalte indizieren.

  3. Erstellen Sie eine einzelne Tabelle mit UDFName, UDFDataType und Value. Wenn eine neue UDF hinzugefügt wird, generieren Sie eine Ansicht, die genau diese Daten abruft und sie in den angegebenen Typ analysiert. Elemente, die die Analysekriterien nicht erfüllen, geben NULL zurück.

  4. Erstellen Sie mehrere UDF-Tabellen, eine pro Datentyp. Wir hätten also Tabellen für UDFStrings, UDFDates usw. Wahrscheinlich würden wir das Gleiche wie # 2 tun und automatisch eine Ansicht generieren, wenn ein neues Feld hinzugefügt wird

  5. XML-Datentypen? Ich habe noch nie damit gearbeitet, aber ich habe gesehen, dass sie erwähnt wurden. Ich bin mir nicht sicher, ob sie mir die gewünschten Ergebnisse liefern würden, insbesondere bei der Leistung.

  6. Etwas anderes?


7
Martin Fowler empfiehlt 2 (vom Benutzer aktualisierbares Schema) oder 5 (indiziertes XML-LOB): martinfowler.com/bliki/UserDefinedField.html
Neil McGuigan

Siehe auch die StackOverflow-Frage zu dynamischen Datenbankschemata .
FloverOwe

Antworten:


49

Wenn Leistung das Hauptanliegen ist, würde ich mit # 6 ... eine Tabelle pro UDF gehen (wirklich, dies ist eine Variante von # 2). Diese Antwort ist speziell auf diese Situation und die Beschreibung der beschriebenen Datenverteilungs- und Zugriffsmuster zugeschnitten.

Vorteile:

  1. Da Sie angeben, dass einige UDFs Werte für einen kleinen Teil des Gesamtdatensatzes haben, bietet eine separate Tabelle die beste Leistung, da diese Tabelle nur so groß ist, wie sie zur Unterstützung der UDF erforderlich ist. Gleiches gilt für die zugehörigen Indizes.

  2. Sie erhalten auch einen Geschwindigkeitsschub, indem Sie die Datenmenge begrenzen, die für Aggregationen oder andere Transformationen verarbeitet werden muss. Durch Aufteilen der Daten in mehrere Tabellen können Sie einige der aggregierenden und anderen statistischen Analysen der UDF-Daten durchführen und dieses Ergebnis dann über einen Fremdschlüssel mit der Mastertabelle verknüpfen, um die nicht aggregierten Attribute zu erhalten.

  3. Sie können Tabellen- / Spaltennamen verwenden, die die tatsächlichen Daten widerspiegeln.

  4. Sie haben die vollständige Kontrolle über die Verwendung von Datentypen, das Überprüfen von Einschränkungen, Standardwerten usw. zum Definieren der Datendomänen. Unterschätzen Sie nicht den Leistungseinbruch, der sich aus der direkten Datentypkonvertierung ergibt. Solche Einschränkungen helfen auch RDBMS-Abfrageoptimierern, effektivere Pläne zu entwickeln.

  5. Sollten Sie jemals Fremdschlüssel verwenden müssen, wird die integrierte deklarative referenzielle Integrität durch die Durchsetzung von Einschränkungen auf Trigger- oder Anwendungsebene nur selten übertroffen.

Nachteile:

  1. Dies könnte viele Tabellen erstellen. Das Erzwingen einer Schematrennung und / oder einer Namenskonvention würde dies erleichtern.

  2. Für den Betrieb der UDF-Definition und -Verwaltung ist mehr Anwendungscode erforderlich. Ich gehe davon aus, dass immer noch weniger Code benötigt wird als für die ursprünglichen Optionen 1, 3 und 4.

Weitere Überlegungen:

  1. Wenn es irgendetwas an der Art der Daten gibt, das für die Gruppierung der UDFs sinnvoll wäre, sollte dies gefördert werden. Auf diese Weise können diese Datenelemente zu einer einzigen Tabelle zusammengefasst werden. Angenommen, Sie haben UDFs für Farbe, Größe und Kosten. Die Tendenz in den Daten ist, dass die meisten Instanzen dieser Daten so aussehen

     'red', 'large', 45.03 

    eher, als

     NULL, 'medium', NULL

    In einem solchen Fall entsteht keine merkliche Geschwindigkeitsstrafe, wenn Sie die 3 Spalten in einer Tabelle kombinieren, da nur wenige Werte NULL sind und Sie vermeiden, 2 weitere Tabellen zu erstellen. Dies sind 2 weniger Verknüpfungen erforderlich, wenn Sie auf alle 3 Spalten zugreifen müssen .

  2. Wenn Sie von einer UDF, die stark bevölkert und häufig verwendet wird, auf eine Leistungswand stoßen, sollte dies für die Aufnahme in die Mastertabelle berücksichtigt werden.

  3. Das logische Tabellendesign kann Sie zu einem bestimmten Punkt führen. Wenn die Anzahl der Datensätze jedoch sehr hoch wird, sollten Sie sich auch ansehen, welche Optionen für die Tabellenpartitionierung von Ihrem RDBMS Ihrer Wahl bereitgestellt werden.


1
Checklisten! Insider-Witz zwischen mir und Phil, ich hoffe, das verstößt nicht gegen die Regeln.
GunnerL3510

Danke, ich denke, ich werde eine Variation davon machen. Die meisten unserer UDF-Daten stammen aus nicht zugeordneten Importfeldern, die nur zu Referenzzwecken verwendet werden müssen. Daher möchte ich diese in einer Tabelle zusammenfassen. Andere UDFs werden nach Bedarf definiert (ich kann sie nicht im Voraus identifizieren. Sie werden normalerweise erstellt, wenn wir einen Prozess ändern oder einige Monate lang etwas Besonderes verfolgen) und werden häufig in Abfragen verwendet. Ich denke, ich werde für jede logische Einheit dieser Werte eine separate Tabelle erstellen.
Rachel

Ich arbeite mit einer Tabelle, die UDFs datiert / versioniert hat. Ich verwende diese Methode, stackoverflow.com/a/123481/328968 , um die neuesten Werte zu erhalten.
Peter

22

Ich habe viel über dieses Problem geschrieben . Die gebräuchlichste Lösung ist das Entity-Attribute-Value-Antimuster, das dem ähnelt, was Sie in Ihrer Option 3 beschreiben. Vermeiden Sie dieses Design wie die Pest .

Was ich für diese Lösung verwende, wenn ich wirklich dynamische benutzerdefinierte Felder benötige, ist, sie in einem XML-Blob zu speichern, damit ich jederzeit neue Felder hinzufügen kann. Um dies zu beschleunigen, erstellen Sie auch zusätzliche Tabellen für jedes Feld, das Sie durchsuchen oder sortieren müssen (Sie haben keine Tabelle pro Feld - nur eine Tabelle pro durchsuchbarem Feld). Dies wird manchmal als invertiertes Indexdesign bezeichnet.

Einen interessanten Artikel aus dem Jahr 2009 über diese Lösung finden Sie hier: http://backchannel.org/blog/friendfeed-schemaless-mysql

Sie können auch eine dokumentorientierte Datenbank verwenden, in der benutzerdefinierte Felder pro Dokument erwartet werden. Ich würde Solr wählen .


1
Können Sie erklären, warum ich Option 3 vermeiden sollte? Ich habe mir einige Ihrer Beispiele angesehen, aber sie sind wirklich nicht die gleichen wie das, was ich versuche zu tun. Ich möchte einfach einen Ort zum Speichern zusätzlicher Daten, nicht einen Ort zum Speichern aller Attribute.
Rachel

2
Für den Anfang, wen würden Sie ein Attribut NICHT NULL machen? Wie würden Sie ein Attribut EINZIGARTIG machen, ohne alle Attribute EINZIGARTIG zu machen? Von dort geht es weiter. Am Ende schreiben Sie Anwendungscode, um Funktionen bereitzustellen, die das RDBMS bereits für Sie bereitstellt, sogar bis zu dem Punkt, dass Sie eine Art Zuordnungsklasse schreiben müssen, um einfach einen logischen Entitätsdatensatz einzufügen und ihn wieder abzurufen.
Bill Karwin

2
Die kurze Antwort lautet "Mischen Sie keine Daten und Metadaten." Das Erstellen von Varchar-Spalten für fieldnameoder tablenamedas Speichern von Metadaten- IDs als Datenzeichenfolgen ist der Beginn vieler Probleme. Siehe auch en.wikipedia.org/wiki/Inner-platform_effect
Bill Karwin

2
@Thomas: Im invertierten Indexdesign können Sie Standardschemalösungen für Datentypen und Einschränkungen wie UNIQUE und FOREIGN KEY verwenden. Diese funktionieren überhaupt nicht, wenn Sie EAV verwenden. Ich stimme invertierten Indexanteilen mit EAV dem Merkmal zu, nicht relational zu sein, nur weil es unterschiedliche Attribute pro Zeile unterstützt, aber es ist ein Kompromisspunkt.
Bill Karwin

2
@thitami, Was ich im Laufe der Jahre gelernt habe, ist, dass jede Lösung die richtige für Ihre App sein könnte. Sogar EAV ist möglicherweise die am wenigsten schlechte Lösung für eine bestimmte App. Sie können keine Optimierungsstrategie auswählen, ohne Ihre Abfragen zu kennen. Jede Art der Optimierung verbessert bestimmte Abfragen auf Kosten anderer Abfragen.
Bill Karwin

10

Ich würde höchstwahrscheinlich eine Tabelle mit folgender Struktur erstellen:

  • varchar Name
  • varchar Typ
  • dezimaler Zahlenwert
  • varchar StringValue
  • Datum Datumswert

Die genauen Arten von Kursen hängen von Ihren Anforderungen ab (und natürlich von den von Ihnen verwendeten DBMS). Sie können auch das NumberValue-Feld (dezimal) für Ints und Boolesche Werte verwenden. Möglicherweise benötigen Sie auch andere Typen.

Sie benötigen einen Link zu den Stammdatensätzen, denen der Wert gehört. Es ist wahrscheinlich am einfachsten und schnellsten, für jede Mastertabelle eine Benutzerfeldtabelle zu erstellen und einen einfachen Fremdschlüssel hinzuzufügen. Auf diese Weise können Sie Stammsätze einfach und schnell nach Benutzerfeldern filtern.

Möglicherweise möchten Sie eine Art von Metadateninformationen haben. Am Ende haben Sie also Folgendes:

Tabelle UdfMetaData

  • int id
  • varchar Name
  • varchar Typ

Tabelle MasterUdfValues

  • int Master_FK
  • int MetaData_FK
  • dezimaler Zahlenwert
  • varchar StringValue
  • Datum Datumswert

Was immer Sie tun, würde ich nicht die Tabellenstruktur ändern sich dynamisch. Es ist ein Alptraum für die Instandhaltung. Ich würde auch keine XML-Strukturen verwenden, sie sind viel zu langsam.


Ich mag deine Strategie und entscheide mich vielleicht dafür, aber wirst du dich 2017 für etwas anderes entscheiden? wie json
maztt

In unserem Projekt haben wir unsere eigenen Datenstrukturen implementiert, die ähnlich wie json serialisiert werden. Es verfügt über eine typsparende Schnittstelle zum Lesen und Schreiben von Daten ohne Casting und mit hervorragender Programmiersprachenintegration. Das ist wirklich super. Es hat das gleiche Problem wie alle diese Arten von "Dokumenten" in Datenbanken. Es ist schwierig, bestimmte Werte abzufragen, und es kann nicht einfach auf Daten außerhalb des "Dokuments" verweisen. Je nach Verwendung ist beides nicht einmal ein Problem.
Stefan Steinegger

Abgesehen davon, was ich 2011 vorgeschlagen habe, ist IMHO immer noch eine gültige Lösung.
Stefan Steinegger

10

Dies klingt nach einem Problem, das möglicherweise besser durch eine nicht relationale Lösung wie MongoDB oder CouchDB gelöst werden kann.

Beide ermöglichen eine dynamische Schemaerweiterung, während Sie gleichzeitig die gewünschte Tupelintegrität beibehalten können.

Ich stimme Bill Karwin zu, das EAV-Modell ist für Sie kein performanter Ansatz. Die Verwendung von Name-Wert-Paaren in einem relationalen System ist an sich nicht schlecht, funktioniert jedoch nur dann gut, wenn das Name-Wert-Paar ein vollständiges Tupel an Informationen enthält. Wenn Sie es verwenden, um eine Tabelle zur Laufzeit dynamisch zu rekonstruieren, werden alle möglichen Dinge schwierig. Das Abfragen wird zu einer Übung in der Pivot-Wartung oder zwingt Sie, die Tupelrekonstruktion in die Objektebene nach oben zu verschieben.

Sie können nicht feststellen, ob ein Nullwert oder ein fehlender Wert ein gültiger Eintrag oder ein fehlender Eintrag ist, ohne Schema-Regeln in Ihre Objektebene einzubetten.

Sie verlieren die Fähigkeit, Ihr Schema effizient zu verwalten. Ist ein 100-stelliger Varchar der richtige Typ für das Feld "Wert"? 200 Zeichen? Sollte es stattdessen nvarchar sein? Es kann ein harter Kompromiss sein, der dazu führt, dass Sie der Dynamik Ihres Sets künstliche Grenzen setzen müssen. So etwas wie "Sie können nur x benutzerdefinierte Felder haben und jedes kann nur y Zeichen lang sein.

Mit einer dokumentenorientierten Lösung wie MongoDB oder CouchDB verwalten Sie alle einem Benutzer zugeordneten Attribute in einem einzigen Tupel. Da Joins kein Thema sind, ist das Leben glücklich, da keiner dieser beiden trotz des Hype gut mit Joins zurechtkommt. Ihre Benutzer können so viele Attribute definieren, wie sie möchten (oder Sie werden es zulassen), und zwar in Längen, die erst schwer zu verwalten sind, wenn Sie ungefähr 4 MB erreichen.

Wenn Sie Daten haben, für die Integrität auf ACID-Ebene erforderlich ist, können Sie die Lösung aufteilen, wobei die Daten mit hoher Integrität in Ihrer relationalen Datenbank und die dynamischen Daten in einem nicht relationalen Speicher gespeichert sind.


6

Selbst wenn Sie einem Benutzer die Möglichkeit geben, benutzerdefinierte Spalten hinzuzufügen, ist es nicht unbedingt so, dass die Abfrage dieser Spalten eine gute Leistung erbringt. Es gibt viele Aspekte, die in das Abfragedesign einfließen und eine gute Leistung ermöglichen. Der wichtigste davon ist die richtige Angabe, was überhaupt gespeichert werden soll. Wollen Sie den Benutzern grundsätzlich ermöglichen, ein Schema ohne Rücksicht auf Spezifikationen zu erstellen und schnell Informationen aus diesem Schema abzuleiten? Wenn ja, ist es unwahrscheinlich, dass eine solche Lösung gut skaliert werden kann, insbesondere wenn Sie dem Benutzer erlauben möchten, numerische Analysen der Daten durchzuführen.

Option 1

IMO dieser Ansatz gibt Ihnen Schema ohne Wissen darüber, was das Schema bedeutet, was ein Rezept für eine Katastrophe und ein Albtraum für Berichtsdesigner ist. Das heißt, Sie müssen über die Metadaten verfügen, um zu wissen, in welcher Spalte welche Daten gespeichert sind. Wenn diese Metadaten durcheinander geraten, können Ihre Daten möglicherweise verloren gehen. Außerdem ist es einfach, die falschen Daten in die falsche Spalte zu setzen. ("Was? String1 enthält den Namen von Klöstern? Ich dachte, es wäre Chalie Sheens Lieblingsdroge.")

Option 3,4,5

IMO, Anforderungen 2, 3 und 4 eliminieren jede Variation eines EAV. Wenn Sie diese Daten abfragen, sortieren oder berechnen müssen, ist ein EAV der Traum von Cthulhu und der Albtraum Ihres Entwicklungsteams und Ihres Datenbankadministrators. EAVs verursachen einen Leistungsengpass und bieten Ihnen nicht die Datenintegrität, die Sie benötigen, um schnell zu den gewünschten Informationen zu gelangen. Abfragen werden schnell zu gordischen Kreuztabellenknoten.

Option 2,6

Das lässt wirklich eine Wahl: Sammeln Sie Spezifikationen und bauen Sie dann das Schema aus.

Wenn der Kunde die beste Leistung für Daten erzielen möchte, die er speichern möchte, muss er mit einem Entwickler zusammenarbeiten, um seine Anforderungen zu verstehen und diese so effizient wie möglich zu speichern. Es kann weiterhin in einer vom Rest der Tabellen getrennten Tabelle mit Code gespeichert werden, der dynamisch ein Formular basierend auf dem Schema der Tabelle erstellt. Wenn Sie über eine Datenbank verfügen, die erweiterte Eigenschaften für Spalten zulässt, können Sie diese sogar verwenden, um dem Formularersteller dabei zu helfen, schöne Beschriftungen, QuickInfos usw. zu verwenden, sodass Sie lediglich das Schema hinzufügen müssen. In jedem Fall müssen die Daten ordnungsgemäß gespeichert werden, damit Berichte effizient erstellt und ausgeführt werden können. Wenn die fraglichen Daten viele Nullen haben, können einige Datenbanken diese Art von Informationen speichern. Beispielsweise,

Wenn dies nur eine Tüte Daten wäre, für die keine Analyse, Filterung oder Sortierung durchgeführt werden sollte, würde ich sagen, dass eine Variation eines EAV den Trick machen könnte. Angesichts Ihrer Anforderungen besteht die effizienteste Lösung darin, die richtigen Spezifikationen zu erhalten, selbst wenn Sie diese neuen Spalten in separaten Tabellen speichern und Formulare dynamisch aus diesen Tabellen erstellen.

Sparse Columns


5
  1. Erstellen Sie mehrere UDF-Tabellen, eine pro Datentyp. Wir hätten also Tabellen für UDFStrings, UDFDates usw. Wahrscheinlich würden wir das Gleiche wie # 2 tun und automatisch eine Ansicht generieren, wenn ein neues Feld hinzugefügt wird

Nach meinen Recherchen helfen Ihnen mehrere Tabellen basierend auf dem Datentyp nicht bei der Leistung. Besonders wenn Sie Massendaten haben, wie 20K- oder 25K-Datensätze mit mehr als 50 UDFs. Die Leistung war am schlechtesten.

Sie sollten eine einzelne Tabelle mit mehreren Spalten verwenden, z.

varchar Name
varchar Type
decimal NumberValue
varchar StringValue
date DateValue

Dies sollte korrekt und positiv bewertet sein. Die vorherige Antwort auf 2011 von Phil ist heute 2016 kein guter Rat mehr.
Yap Kai Lun Leon

Kann ich ein einfaches Beispiel dafür bekommen, wie man einen solchen Prozess in SQL ausführt?
Niroj

Entschuldigen Sie die späte Antwort, aber Sie möchten die Datenbankstruktur für dieselbe. Ich habe dich nicht @Niroj bekommen. Können Sie bitte im Detail erklären, was Sie wollen.
Amit Auftragnehmer

4

Dies ist eine problematische Situation, und keine der Lösungen erscheint "richtig". Option 1 ist jedoch wahrscheinlich sowohl in Bezug auf die Einfachheit als auch in Bezug auf die Leistung die beste.

Dies ist auch die Lösung, die in einigen kommerziellen Unternehmensanwendungen verwendet wird.

BEARBEITEN

Eine andere Option, die jetzt verfügbar ist, aber nicht vorhanden war (oder zumindest nicht ausgereift war), als die Frage ursprünglich gestellt wurde, ist die Verwendung von JSON-Feldern in der Datenbank.

Viele relationale DBs unterstützen jetzt JSON-basierte Felder (die eine dynamische Liste von Unterfeldern enthalten können) und ermöglichen das Abfragen dieser Felder

Postgress

MySQL


1
Ich hasse die Idee, möglicherweise Hunderte von nicht verwendeten Spalten zu erstellen. Es widerspricht dem, was ich über SQL-Datenbankdesign gelernt und gelesen habe. Derzeit haben wir über 1300 verschiedene benutzerdefinierte Werte, von denen viele lediglich Duplikate vorhandener Elemente sind, die unterschiedlich benannt sind.
Rachel

1300 verschiedene UDF für eine einzelne Tabelle? Hat jeder Benutzer die Möglichkeit, UDF hinzuzufügen, oder nur eine Art Hauptbenutzer?
Ophir Yoktan

Es ist Teil des Importprozesses ... es fügt einem benutzerdefinierten Feld alle nicht zugeordneten Daten hinzu. Da sich niemand die Zeit nimmt, nicht zugeordnete Daten vorhandenen UDF-Feldern zuzuordnen, werden nur neue erstellt, und im Laufe der Jahre wurden viele hinzugefügt.
Rachel

2

Ich habe Erfahrung oder 1, 3 und 4 und sie alle enden entweder chaotisch, wobei nicht klar ist, was die Daten sind, oder wirklich kompliziert mit einer weichen Kategorisierung, um die Daten in dynamische Arten von Datensätzen aufzuteilen.

Ich wäre versucht, XML auszuprobieren. Sie sollten in der Lage sein, Schemas gegen den Inhalt der XML zu erzwingen, um die Datentypisierung usw. zu überprüfen. Dies hilft dabei, unterschiedliche Sätze von UDF-Daten zu speichern. In neueren Versionen von SQL Server können Sie XML-Felder indizieren, was die Leistung verbessern soll. (siehe http://blogs.technet.com/b/josebda/archive/2009/03/23/sql-server-2008-xml-indexing.aspx ) zum Beispiel


Ehrlich gesagt habe ich mich überhaupt nicht mit XML befasst. Der Hauptnachteil dabei ist, dass ich lernen muss, wie es funktioniert und wie man dagegen abfragt, und ich habe gehört, dass die Leistung schlechter sein kann als die anderen Optionen
Rachel

1
Ich würde es vermeiden, XML dafür zu verwenden: Es kann den Job erledigen, und ich habe in der Vergangenheit so etwas in XML implementiert, aber die Leistung wurde ziemlich schlecht, als die Datenstrukturen wuchsen und die Codekomplexität hoch war.
Kell

2

Wenn Sie SQL Server verwenden, übersehen Sie nicht den SQL-Variantentyp. Es ist ziemlich schnell und sollte Ihren Job machen. Andere Datenbanken haben möglicherweise etwas Ähnliches.

XML-Datentypen sind aus Leistungsgründen nicht so gut. Wenn Sie Berechnungen auf dem Server durchführen, müssen Sie diese ständig deserialisieren.

Option 1 klingt schlecht und sieht grob aus, aber in Bezug auf die Leistung kann dies die beste Wahl sein. Ich habe bereits Tabellen mit Spalten mit dem Namen Field00-Field99 erstellt, da Sie die Leistung einfach nicht übertreffen können. Möglicherweise müssen Sie auch Ihre INSERT-Leistung berücksichtigen. In diesem Fall ist dies auch die richtige Wahl. Sie können jederzeit Ansichten für diese Tabelle erstellen, wenn Sie möchten, dass sie ordentlich aussieht!


Vielen Dank, ich werde einen weiteren Blick auf SQL-Varianten werfen. Meine größte Sorge ist die Leistung und ich bin mir nicht sicher, wie es damit umgehen würde, besonders wenn wir über 50mil Reihen sprechen
Rachel

Ich habe gerade herausgefunden, dass sql_varients nicht mit der LIKE-Klausel verwendet werden kann ... das ist ein großer Nachteil für mich. Natürlich, wenn ich für jede UDF eine Ansicht erstelle dann könnte ich es in dem entsprechenden Datentyp gegossen basierend auf SQL_VARIANT_PROPERTY (Wert ‚Basetype‘) ... immer noch, so scheint wie seine schlecht für die Leistung
Rachel

Sie können LIKE verwenden, müssen jedoch zuerst den Wert umwandeln. LIKE funktioniert nur mit Varchars, daher müssen Sie Ihre sql_variant in einen Varchar umwandeln. Solange Sie wissen, ob Ihre UDF ein Varchar ist (z. B. weil der Typ an einem anderen Ort gespeichert ist), können Sie alle Ihre Zeilen nach Varchars filtern und dann Ihre LIKE-Abfrage umwandeln und ausführen: z. Wählen Sie * FROM MyTable, wobei varianten_type = 'v' Cast (variantenwert als varchar (max)) LIKE 'Blah%'. Auf diese Weise konvertieren Sie keine Ints usw. in Zeichenfolgen, die Sie verlangsamen würden.
Tim Rogers

Ich müsste einige Tests durchführen, um zu sehen, wie die Leistung dabei ist, insbesondere bei Millionen von Zeilen. Kennen Sie Online-Artikel zur Leistung mit sql_varients? Besonders beim Casting und bei sehr vielen Platten?
Rachel


1

Ich habe dies in der Vergangenheit sehr erfolgreich mit keiner dieser Optionen geschafft (Option 6? :)).

Ich erstelle ein Modell, mit dem die Benutzer spielen können (als XML speichern und über ein benutzerdefiniertes Modellierungswerkzeug verfügbar machen) und aus dem Modell generierte Tabellen und Ansichten, um die Basistabellen mit den benutzerdefinierten Datentabellen zu verbinden. Jeder Typ hätte also eine Basistabelle mit Kerndaten und eine Benutzertabelle mit benutzerdefinierten Feldern.

Nehmen Sie als Beispiel ein Dokument: Typische Felder sind Name, Typ, Datum, Autor usw. Dies wird in die Kerntabelle aufgenommen. Dann würden Benutzer ihre eigenen speziellen Dokumenttypen mit ihren eigenen Feldern definieren, z. B. contract_end_date, erneueral_clause, bla bla bla. Für dieses benutzerdefinierte Dokument gibt es die Kerndokumenttabelle, die xcontract-Tabelle, die mit einem gemeinsamen Primärschlüssel verknüpft ist (sodass der xcontracts-Primärschlüssel auch für den Primärschlüssel der Kerntabelle fremd ist). Dann würde ich eine Ansicht generieren, um diese beiden Tabellen zu verpacken. Die Leistung beim Abfragen war schnell. Zusätzliche Geschäftsregeln können ebenfalls in die Ansichten eingebettet werden. Das hat bei mir sehr gut funktioniert.


1

Unsere Datenbank unterstützt eine SaaS-App (Helpdesk-Software), in der Benutzer über 7.000 "benutzerdefinierte Felder" haben. Wir verwenden einen kombinierten Ansatz:

  1. (EntityID, FieldID, Value)Tabelle zum Durchsuchen der Daten
  2. Ein JSON-Feld in der entitiesTabelle, das alle Entitätswerte enthält und zur Anzeige der Daten verwendet wird. (Auf diese Weise benötigen Sie nicht eine Million JOINs, um die Werte zu erhalten).

Sie könnten # 1 weiter aufteilen, um eine "Tabelle pro Datentyp" zu erhalten, wie diese Antwort nahelegt. Auf diese Weise können Sie sogar Ihre UDFs indizieren.

PS Ein paar Worte, um den "Entity-Attribute-Value" -Ansatz zu verteidigen, den jeder immer wieder verprügelt. Wir haben # 1 ohne # 2 seit Jahrzehnten verwendet und es hat gut funktioniert. Manchmal ist es eine Geschäftsentscheidung. Haben Sie Zeit, Ihre App neu zu schreiben und die Datenbank neu zu gestalten, oder können Sie ein paar Dollar auf Cloud-Server werfen, die heutzutage wirklich billig sind? Übrigens, als wir den Ansatz Nr. 1 verwendeten, enthielt unsere Datenbank Millionen von Entitäten, auf die Hunderttausende von Benutzern zugegriffen hatten, und ein 16-GB-Dual-Core-Datenbankserver lief einwandfrei


Hallo @Alex, ich bin auf ein ähnliches Problem gestoßen. Wenn ich es gut verstehe, haben Sie: 1) eine custom_fieldsTabelle, in der Werte wie 1 => last_concert_year, 2 => band, 3 => gespeichert sind , musicund dann eine custom_fields_valuesTabelle mit den Werten 001, 1, 1976 002, 1, 1977 003, 2, Iron Maiden003, 3 , Metal Hoffnung das Beispiel macht Sinn für Sie und entschuldigen uns für die Formatierung!
Thitami

@ Thitami nicht genau. Nach Ihrem Beispiel: Ich habe eine bandsTabelle mit einer Zeile, 1,'Iron Maiden'dann custom_fieldsmit Zeilen, 1,'concert_year' | 2,'music'dann custom_fields_valuesmit Zeilen1,1,'1977'|1,2,'metal'
Alex

0

In den Kommentaren habe ich gesehen, dass Sie gesagt haben, dass die UDF-Felder importierte Daten sichern sollen, die vom Benutzer nicht richtig zugeordnet wurden.

Möglicherweise besteht eine andere Möglichkeit darin, die Anzahl der von jedem Benutzer erstellten UDFs zu verfolgen und sie zur Wiederverwendung von Feldern zu zwingen, indem angegeben wird, dass sie 6 benutzerdefinierte Felder (oder eine andere, gleichermaßen zufällige Grenze) verwenden können.

Wenn Sie mit einem solchen Datenbankstrukturierungsproblem konfrontiert sind, ist es oft am besten, zum grundlegenden Design der Anwendung (in Ihrem Fall zum Importsystem) zurückzukehren und einige weitere Einschränkungen vorzunehmen.

Was ich jetzt tun würde, ist Option 4 (BEARBEITEN) mit dem Hinzufügen eines Links zu Benutzern:

general_data_table
id
...


udfs_linked_table
id
general_data_id
udf_id


udfs_table
id
name
type
owner_id --> Use this to filter for the current user and limit their UDFs
string_link_id --> link table for string fields
int_link_id
type_link_id

Stellen Sie jetzt sicher, dass Sie Ansichten erstellen, um die Leistung zu optimieren und Ihre Indizes richtig zu machen. Durch diesen Normalisierungsgrad wird der DB-Footprint kleiner, Ihre Anwendung jedoch komplexer.


0

Ich würde # 4 empfehlen, da diese Art von System in Magento verwendet wurde , einer hoch akkreditierten E-Commerce-CMS-Plattform. Verwenden Sie eine einzelne Tabelle, um Ihre benutzerdefinierten Felder mithilfe der Spalten fieldId & label zu definieren . Dann hat getrennte Tabellen für jeden Datentyp und in jedem dieser Tabellen hat einen Index , die Indizes von fieldID und den Datentyp Wert Spalten. Verwenden Sie dann in Ihren Abfragen Folgendes:

SELECT *
FROM FieldValues_Text
WHERE fieldId IN (
    SELECT fieldId FROM Fields WHERE userId=@userId
)
AND value LIKE '%' + @search + '%'

Dies wird meiner Meinung nach die bestmögliche Leistung für benutzerdefinierte Typen gewährleisten.

Nach meiner Erfahrung habe ich an mehreren Magento-Websites gearbeitet, die monatlich Millionen von Benutzern bedienen, Tausende von Produkten mit benutzerdefinierten Produktattributen hosten und die Datenbank die Arbeitslast auch für Berichte problemlos handhaben kann.

Für die Berichterstellung können Sie die BeschriftungswertePIVOT Ihrer Fields- Tabelle in Spaltennamen konvertieren und dann Ihre Abfrageergebnisse aus jeder Datentabellentabelle in diese geschwenkten Spalten schwenken.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.