Abfragen hierarchischer Daten mit Postgres
15.04.2024
•
Wietsche Calitz
Hierarchische Daten sind weit verbreitet und einfach zu speichern, aber ihre Abfrage kann herausfordernd sein. Dieser Beitrag wird Sie durch den Prozess…
Hierarchische Daten sind weit verbreitet und einfach zu speichern, aber ihre Abfrage kann herausfordernd sein. Dieser Beitrag wird Sie durch den Prozess der Navigation in hierarchischen Daten in Postgres führen. Es ist erwähnenswert, dass diese Anweisungen auch auf andere Datenbanksysteme anwendbar sind, die Common Table Expressions unterstützen, wie sie in SQL:1999 eingeführt wurden.
Beispieldatensatz
Der Datensatz, den wir verwenden werden, ist eine gute Einführung für diejenigen, die mit hierarchischen Daten, auch bekannt als Eltern-Kind-Beziehungen, nicht vertraut sind. Das Beispiel sollte selbsterklärend sein.
Entwickeln Sie die Abfrage
Beginnen wir mit einer Frage: „Auf welchem Kontinent liegt Brüssel?“ Anstatt das SQL sofort bereitzustellen, begleite mich bei der Entwicklung einer Strategie, die als Grundlage für die Beantwortung komplexerer Fragen dienen kann.
Schritt 1: Identifizieren Sie den Startknoten
Schritt 2: Beziehen Sie das unmittelbare Elternteil (oder Kinder, wenn Sie in die entgegengesetzte Richtung navigieren)
Schritt 3: Mach die Abfrage rekursiv
Postgres ermöglicht die Erstellung rekursiver Abfragen, die auf ihren eigenen Ergebnissen ausgeführt werden. In diesem Szenario besteht unser Ziel darin, die gemeinsame Tabellenexpressionsvorlage für Vorfahren so anzupassen, dass sie sich selbst referenziert. Diese Anpassung wird die Abfrage veranlassen, das im Schritt 2 beschriebene Verfahren zu wiederholen, bis keine weiteren Zeilen zurückgegeben werden.
Stellen Sie sicher, dass Sie diesen Schritt verstehen, bevor Sie fortfahren. Es kann etwas verwirrend sein!
Schritt 4: Fügen Sie einen Tiefe-Zähler hinzu
Der Tiefe-Zähler beginnt bei null und erhöht sich mit jedem hinzugefügten Vorfahren im Output.
Mit etwas mehr Code können Sie einen Filter festlegen, um den Kontinent basierend auf der zweitgrößten Tiefe zurückzugeben:
Von Oben Nach Unten
Jetzt lassen Sie uns eine umgekehrte Navigation in Betracht ziehen, zum Beispiel das Zurückgeben von Städten in Asien. Wenn wir in Schritt 3 der obigen Anweisungen überspringen, würde es wie folgt erscheinen. Achten Sie darauf, wie sich die Richtung der Navigation ändert, indem Sie die Join-Bedingungen umkehren. Die Bedingung ancestor.parent_id = dataset.id navigiert nach oben, während ancestor.id = dataset.parent_id nach unten navigiert.
Aggregation
Zum Beispiel die Berechnung der Summe der Bevölkerungen in europäischen Städten:
Hinweise zur Leistung
Rekursionstiefe
Begrenzen Sie die Rekursionstiefe, um potenziell teure Abfragen zu vermeiden. Ihr Verständnis der Daten ist entscheidend für diesen Prozess. Aus dem obigen Beispiel wissen wir, dass die maximale Tiefe 3 beträgt. Durch die Begrenzung der Rekursion können Sie sich vor versteckten Datenqualitätsproblemen schützen:
ancestor AS (
SELECT *, 0 AS depth FROM start_node
UNION
SELECT dataset.*, depth+1 FROM dataset, ancestor
WHERE (ancestor.parent_id = dataset.id)
AND depth <= 3
)
Indizes
Wenn Sie mit persistenten Tabellen arbeiten, besteht der allgemeine Ansatz darin, Indizes für die Joinkonditionen zu erstellen, beispielsweise durch das Hinzufügen eines Index auf ‚id‘ und ‚parent_id‘. Bei kleinen Datensätzen könnte dies jedoch keinen signifikanten Unterschied machen.
Relationale vs. Graphdatenbanken
Postgres, ein Relational Database Management System (RDBMS), ist im Vergleich zu Graphdatenbanken wie Neo4j nicht die beste Wahl für die Navigation in komplexen Hierarchien. Dennoch ist die hierarchische Datenstruktur, mit der wir oft arbeiten, nur ein kleiner Teil eines größeren Bereichs. Dieser Bereich besteht hauptsächlich aus einfacheren Datenstrukturen, die gut für relationale Datenbanken geeignet sind. Daher ist es wahrscheinlich, dass Sie, es sei denn, der gesamte Bereich begünstigt graphbasierte Strukturen, die Nutzung dessen, was das RDBMS bietet, optimieren müssen.
Zusammenfassung
Denken Sie an diese Schritte, wenn Sie das nächste Mal auf einen hierarchischen Datensatz in Postgres stoßen:
Beginnen Sie damit, Ihren Ausgangspunkt zu identifizieren. Das bedeutet, den genauen Knoten zu bestimmen, von dem aus Sie Ihren Datenabrufprozess beginnen werden.
Bestimmen Sie dann das unmittelbare Eltern- oder Kindknoten, abhängig von der Richtung, in die Sie navigieren möchten. Dies ist entscheidend, um den Weg Ihrer Navigation zu gestalten.
Sobald Sie Ihre Richtung bestimmt haben, passen Sie Ihre Abfrage an, um sie rekursiv zu machen. Dadurch kann Ihre Abfrage wiederholt werden, bis keine weiteren Zeilen zurückgegeben werden.
Integrieren Sie einen Tiefe-Zähler in Ihre Abfrage. Dies wird festgehalten, wie viele Schichten Sie in die Datenbankstruktur navigiert haben, was klare Einblicke in die Komplexität Ihrer Daten bietet.
Schließlich, falls nötig, können Sie die Ergebnisse filtern oder aggregieren, um das Endprodukt Ihrer Abfrage anzupassen.
Latest
Portable by design: Rethinking data platforms in the age of digital sovereignty
Build a portable, EU-compliant data platform and avoid vendor lock-in—discover our cloud-neutral stack in this deep-dive blog.
Cloud-Unabhängigkeit: Test eines europäischen Cloud-Anbieters gegen die Giganten
Kann ein europäischer Cloud-Anbieter wie Ionos AWS oder Azure ersetzen? Wir testen es – und finden überraschende Vorteile in Bezug auf Kosten, Kontrolle und Unabhängigkeit.
Vermeide schlechte Daten von Anfang an
Das Erfassen aller Daten ohne Qualitätsprüfungen führt zu wiederkehrenden Problemen. Priorisieren Sie die Datenqualität von Anfang an, um nachgelagerte Probleme zu vermeiden.