Gute Übersichten
Im Allgemeinen treffen Sie eine Entscheidung zwischen schnellen Lesezeiten (z. B. verschachtelter Satz) oder schnellen Schreibzeiten (Adjazenzliste). Normalerweise erhalten Sie eine Kombination der folgenden Optionen, die Ihren Anforderungen am besten entspricht. Im Folgenden finden Sie einige ausführliche Informationen:
- Noch ein Vergleich zwischen verschachtelten Intervallen und Adjazenzliste : Der beste Vergleich von Adjazenzliste, materialisiertem Pfad, verschachtelter Menge und verschachteltem Intervall, den ich gefunden habe.
- Modelle für hierarchische Daten : Folien mit guten Erklärungen zu Kompromissen und Beispielverwendung
- Darstellung von Hierarchien in MySQL : Insbesondere ein sehr guter Überblick über Nested Set
- Hierarchische Daten in RDBMS : die umfassendsten und am besten organisierten Links, die ich gesehen habe, aber nicht viel zur Erklärung
Optionen
Eine, die mir bekannt ist und allgemeine Merkmale:
- Adjazenzliste :
- Spalten: ID, ParentID
- Einfach zu implementieren.
- Günstiger Knoten wird verschoben, eingefügt und gelöscht.
- Teuer, um das Level, die Abstammung und die Nachkommen, den Pfad zu finden
- Vermeiden Sie N + 1 über Common Table Expressions in Datenbanken, die diese unterstützen
- Verschachteltes Set (auch bekannt als Modified Preorder Tree Traversal )
- Spalten: Links, rechts
- Billige Abstammung, Nachkommen
- Sehr teure
O(n/2)
Verschiebungen, Einfügungen, Löschungen aufgrund flüchtiger Codierung
- Brückentabelle (auch bekannt als Closure Table / w-Trigger )
- Verwendet eine separate Verknüpfungstabelle mit: Vorfahr, Nachkomme, Tiefe (optional)
- Billige Vorfahren und Nachkommen
- Schreibt Kosten
O(log n)
(Größe des Teilbaums) für das Einfügen, Aktualisieren und Löschen - Normalisierte Codierung: Gut für RDBMS-Statistiken und Abfrageplaner in Joins
- Erfordert mehrere Zeilen pro Knoten
- Abstammungsspalte (auch bekannt als Materialized Path , Path Enumeration)
- Spalte: Abstammung (zB / Elternteil / Kind / Enkel / etc ...)
- Günstige Nachkommen per Präfixabfrage (zB
LEFT(lineage, #) = '/enumerated/path'
) - Schreibt Kosten
O(log n)
(Größe des Teilbaums) für das Einfügen, Aktualisieren und Löschen - Nicht relational: basiert auf dem Array-Datentyp oder dem serialisierten Zeichenfolgenformat
- Verschachtelte Intervalle
- Wie verschachtelte Menge, jedoch mit real / float / decimal, damit die Codierung nicht flüchtig ist (kostengünstiges Verschieben / Einfügen / Löschen)
- Hat Real / Float / Dezimaldarstellung / Präzisionsprobleme
- Die Matrixcodierungsvariante fügt die Ahnencodierung (materialisierter Pfad) "kostenlos" hinzu, jedoch mit zusätzlicher Schwierigkeit der linearen Algebra.
- Flacher Tisch
- Eine modifizierte Adjazenzliste, die jedem Datensatz eine Spalte für Stufe und Rang (z. B. Reihenfolge) hinzufügt.
- Günstig zu iterieren / paginieren
- Teuer verschieben und löschen
- Gute Verwendung: Diskussionsfäden - Foren / Blog-Kommentare
- Mehrere Abstammungsspalten
- Spalten: Eine für jede Abstammungsstufe bezieht sich auf alle Eltern bis zur Wurzel, Stufen von der Stufe des Gegenstands werden auf NULL gesetzt
- Billige Vorfahren, Nachkommen, Level
- Billig einfügen, löschen, bewegen der Blätter
- Teures Einfügen, Löschen, Verschieben der internen Knoten
- Harte Grenze, wie tief die Hierarchie sein kann
Datenbankspezifische Hinweise
MySQL
Orakel
- Verwenden Sie CONNECT BY , um Adjazenzlisten zu durchlaufen
PostgreSQL
- ltree-Datentyp für Materialized Path
SQL Server
- Allgemeine Zusammenfassung
- 2008 bietet HierarchyId- Datentyp scheint beim Lineage Column-Ansatz zu helfen und die darstellbare Tiefe zu erweitern.
sql
database
tree
relational-database
hierarchical-data
Orangepips
quelle
quelle
Closure Tables
überlegen sindAdjacency List
,Path Enumeration
undNested Sets
in Bezug auf die Benutzerfreundlichkeit (und ich nehme an Leistung als auch).Antworten:
Meine Lieblingsantwort ist wie im ersten Satz dieses Threads vorgeschlagen. Verwenden Sie eine Adjazenzliste, um die Hierarchie zu verwalten, und verwenden Sie verschachtelte Mengen, um die Hierarchie abzufragen.
Das Problem bestand bisher darin, dass die Coversion-Methode von einer Adjacecy-Liste zu verschachtelten Sets furchtbar langsam war, da die meisten Leute die extreme RBAR-Methode verwenden, die als "Push Stack" bekannt ist, um die Konvertierung durchzuführen, und als viel zu teuer angesehen wurde um das Nirvana der Einfachheit der Wartung durch die Adjacency List und der beeindruckenden Leistung verschachtelter Sets zu erreichen. Infolgedessen müssen sich die meisten Menschen mit dem einen oder anderen zufrieden geben, insbesondere wenn es mehr als beispielsweise miese 100.000 Knoten gibt. Die Verwendung der Push-Stack-Methode kann einen ganzen Tag dauern, um die Konvertierung für eine MLM-Hierarchie von kleinen Millionen Knoten durchzuführen.
Ich dachte, ich würde Celko ein bisschen Konkurrenz machen, indem ich eine Methode entwickeln würde, um eine Adjazenzliste in verschachtelte Sätze mit Geschwindigkeiten umzuwandeln, die einfach unmöglich erscheinen. Hier ist die Leistung der Push-Stack-Methode auf meinem i5-Laptop.
Und hier ist die Dauer für die neue Methode (mit der Push-Stack-Methode in Klammern).
Ja das ist richtig. 1 Million Knoten in weniger als einer Minute und 100.000 Knoten in weniger als 4 Sekunden konvertiert.
Sie können sich über die neue Methode informieren und eine Kopie des Codes unter der folgenden URL erhalten. http://www.sqlservercentral.com/articles/Hierarchy/94040/
Ich habe auch eine "voraggregierte" Hierarchie mit ähnlichen Methoden entwickelt. MLM'er und Personen, die Stücklisten erstellen, werden an diesem Artikel besonders interessiert sein. http://www.sqlservercentral.com/articles/T-SQL/94570/
Wenn Sie vorbeischauen, um sich einen der Artikel anzusehen, springen Sie in den Link "An der Diskussion teilnehmen" und teilen Sie mir Ihre Meinung mit.
quelle
Dies ist eine sehr teilweise Antwort auf Ihre Frage, aber ich hoffe immer noch nützlich.
Microsoft SQL Server 2008 implementiert zwei Funktionen, die für die Verwaltung hierarchischer Daten äußerst nützlich sind:
Schauen Sie sich für Starts "Modellieren Ihrer Datenhierarchien mit SQL Server 2008" von Kent Tegels auf MSDN an. Siehe auch meine eigene Frage: Rekursive Abfrage derselben Tabelle in SQL Server 2008
quelle
Dieser Entwurf wurde noch nicht erwähnt:
Mehrere Abstammungsspalten
Obwohl es Einschränkungen gibt, ist es sehr einfach und sehr effizient, wenn Sie sie ertragen können. Eigenschaften:
Hier folgt ein Beispiel - taxonomischer Vogelbaum, daher ist die Hierarchie Klasse / Ordnung / Familie / Gattung / Art - Art ist die niedrigste Ebene, 1 Zeile = 1 Taxon (was im Fall der Blattknoten der Art entspricht):
und das Beispiel der Daten:
Dies ist großartig, da Sie auf diese Weise alle erforderlichen Vorgänge auf sehr einfache Weise ausführen können, solange die internen Kategorien ihre Ebene im Baum nicht ändern.
quelle
Adjazenzmodell + Modell verschachtelter Mengen
Ich habe mich dafür entschieden, weil ich einfach neue Elemente in den Baum einfügen konnte (Sie benötigen nur die ID eines Zweigs, um ein neues Element einzufügen) und es auch ziemlich schnell abfragen konnte.
parent
Spalte ab.lft
Zwischen-lft
undrgt
übergeordnetes Element vorhanden sind .lft
kleiner als der Knotenlft
undrgt
größer als der Knoten sind,rgt
und sortieren die nachparent
.Ich musste den Zugriff auf und das Abfragen des Baums schneller als das Einfügen machen, deshalb habe ich mich dafür entschieden
Das einzige Problem besteht darin, die Spalten
left
undright
beim Einfügen neuer Elemente zu korrigieren. Nun, ich habe eine gespeicherte Prozedur dafür erstellt und sie jedes Mal aufgerufen, wenn ich ein neues Element eingefügt habe, was in meinem Fall selten war, aber sehr schnell ist. Ich habe die Idee aus dem Buch von Joe Celko, und die gespeicherte Prozedur und wie ich darauf gekommen bin, wird hier in DBA SE https://dba.stackexchange.com/q/89051/41481 erklärtquelle
children
unddescendants
.left
undright
werden verwendet, um die Nachkommen zu finden.Wenn Ihre Datenbank Arrays unterstützt, können Sie auch eine Abstammungsspalte oder einen materialisierten Pfad als Array übergeordneter IDs implementieren.
Speziell mit Postgres können Sie dann die Set-Operatoren verwenden, um die Hierarchie abzufragen und mit GIN-Indizes eine hervorragende Leistung zu erzielen. Dies macht das Finden von Eltern, Kindern und Tiefe in einer einzigen Abfrage ziemlich trivial. Updates sind auch ziemlich überschaubar.
Ich habe eine vollständige Beschreibung der Verwendung von Arrays für materialisierte Pfade, wenn Sie neugierig sind.
quelle
Dies ist wirklich eine Frage mit quadratischem Stift und rundem Loch.
Wenn relationale Datenbanken und SQL der einzige Hammer sind, den Sie haben oder verwenden möchten, sind die bisher veröffentlichten Antworten angemessen. Verwenden Sie jedoch ein Tool für den Umgang mit hierarchischen Daten. Die Grafikdatenbank ist ideal für komplexe hierarchische Daten.
Die Ineffizienzen des relationalen Modells zusammen mit der Komplexität einer Code- / Abfragelösung zum Abbilden eines Diagramms / hierarchischen Modells auf ein relationales Modell sind im Vergleich zu der Leichtigkeit, mit der eine Diagrammdatenbanklösung das gleiche Problem lösen kann, einfach nicht die Mühe wert.
Betrachten Sie eine Stückliste als eine gemeinsame hierarchische Datenstruktur.
Kürzester Weg zwischen zwei Unterbaugruppen : Einfacher Graph-Traversal-Algorithmus. Akzeptable Pfade können anhand von Kriterien qualifiziert werden.
Ähnlichkeit : Wie groß ist die Ähnlichkeit zwischen zwei Baugruppen? Führen Sie eine Durchquerung beider Teilbäume durch und berechnen Sie den Schnittpunkt und die Vereinigung der beiden Teilbäume. Der Prozentsatz ähnlich ist der Schnittpunkt geteilt durch die Gewerkschaft.
Transitive Schließung : Gehen Sie über den Unterbaum und fassen Sie die interessierenden Felder zusammen, z. B. "Wie viel Aluminium befindet sich in einer Unterbaugruppe?"
Ja, Sie können das Problem mit SQL und einer relationalen Datenbank lösen. Es gibt jedoch viel bessere Ansätze, wenn Sie bereit sind, das richtige Werkzeug für den Job zu verwenden.
quelle
Ich verwende PostgreSQL mit Schließungstabellen für meine Hierarchien. Ich habe eine universelle gespeicherte Prozedur für die gesamte Datenbank:
Dann erstelle ich für jede Tabelle, in der ich eine Hierarchie habe, einen Trigger
Zum Auffüllen einer Abschlusstabelle aus einer vorhandenen Hierarchie verwende ich diese gespeicherte Prozedur:
Schließungstabellen werden mit 3 Spalten definiert - ANCESTOR_ID, DESCENDANT_ID, DEPTH. Es ist möglich (und ich rate sogar), Datensätze mit demselben Wert für ANCESTOR und DESCENDANT und einem Wert von Null für DEPTH zu speichern. Dies vereinfacht die Abfragen zum Abrufen der Hierarchie. Und sie sind in der Tat sehr einfach:
quelle