bannkreis.de

Für eine handvoll XML (Pt.1)

In der letzten Zeit ertappe ich mich öfters dabei, dass meine Gedanken wieder um native XML-Datenbanken kreisen und wie man sie einsetzen kann. Eine Art Deja'vu für mich, waren wir, d.h die kleine Softwareschmiede in der ich mein Tageswerk leiste, doch bereits vor einigen Jahren  soweit, Konzepte rund um diese neue und (inzwischen nicht mehr sonderlich) aufstrebende Datenbankgattung zusammen zu schustern.

Der Hintergrund: Wir stellen ein Content Management System her, das mit einer Vielzahl unterschiedlicher Datenbanksysteme umgehen kann. Zu einem gewissen Zeitpunkt war es an uns zu entscheiden, ob wir unseren Schwerpunkt eher auf relationale Datenbanken oder auf XML-Datenbanken verlagern wollen. Für letztere waren wir sogar bereits soweit, eine Partnerschaft mit einem kommerziellen Hersteller von XML-Datenbanken anzubahnen, falls wir uns für diesen Weg entscheiden würden.
Seinerzeit haben wir uns hauptsächlich aufgrund zweier Argumente in Richtung relationaler Systeme entwickelt, nämlich dass a) relationale Systeme natürlich viel verbreiteter, bekannter und dadurch auch nach allgemeiner Meinung vertrauenswürdiger sind und b) dass kein Benefit beim Einsatz von XML-Datenbanken gegenüber relationalen Systemen erkennbar war.

Punkt 2 würde ich heute revidieren, und das ist wahrscheinlich auch der Grund weshalb ich wieder in diese Richtung grüble. Die große Schwachstelle bei relationalen Systemen mit komplex strukturierten Content-Daten ist...man mag es kaum glauben...SQL. RDBMS-Puristen werden mich wahrscheinlich für diese Aussage kreuzigen, aber sie (die Abfragesprache) ist von ihrer Struktur her einfach nicht dafür geschaffen, hierarchisch angeordnete Daten abzufragen.

Mal sehen ob ich das anhand unseres Anwendungsfalls konkretisiert bekomme. Unser System basiert auf dem "Dokument" als Hauptentität das eine unbestimmte, variable Anzahl an Feldern besitzen kann. Es gibt keine vorgegebene Struktur, jedes Dokument besitzt seine eigene Feldliste, eine Konzession an die Flexibilität des Systems in welchem jeder Kunde für sich selbst entscheiden kann, welche Daten er verwalten will (Lotus-Entwicklern wird diese Strategie bekannt vorkommen....). Wie bildet man soetwas auf eine relationale Struktur ab?

Eine einfache Dokument-Tabelle reicht nicht, da ich dort für Felder keine festen Spalten definieren kann, die müssen wie gesagt variabel sein. Also macht man dies indem man Dokumente und Felder in zwei separaten Tabellen unterbringt die über eine 1:n-Beziehung miteinander verbunden sind. Die Feld-Tabelle besitzt mindestens drei Spalten um dynamisch anlegbare Felder abbilden zu können:

- Eine Spalte als Foreign-Key, welche die Verbindung zur Dokument-Tabelle benötigt
- Eine Spalte welche den Namen des Feldes beinhaltet. Zusammen mit der ersten Spalte bildet sie den Primary Key der Tabelle
- Eine Spalte enthalten den Inhalt des Feldes

Bis hierher noch keine Probleme in Sicht. Nun will ich meinen so gespeicherten Datenbestand abfragen. Da die Felder die Business-Daten der Dokumente enthalten wird so ziemlich jede Abfrage auf sie verweisen. Man würde also, wenn man Dokumente sucht die in einem bestimmten Feld einen bestimmten Wert enthalten, folgendes in SQL formulieren:

select documents.*
from documents, fields
where
documents.id = fields.docid and
fields.name='fieldname' and fields.value='fieldvalue'

Das ist für eine so simple Operation zwar schon ziemlich viel Text, aber eigentlich immernoch leicht verstehbar. Man sollte denken dass es hier aus kein schwieriger Weg sein kann, diese Abfrage leicht zu erweitern, z.B. statt auf eines nun auf zwei Feldwerte gleichzeitig abzufragen:

select documents.*
from documents, fields
where
documents.id = fields.docid and
(fields.name='fieldname1' and fields.value='fieldvalue1') and
(fields.name='fieldname2' and fields.value='fieldvalue2')

Alles cool? Mitnichten, diese Abfrage funktioniert nicht. Niemals kann in einer Ergebniszeile ein Feldname gleichzeitig "fieldname1" und "fieldname2" sein, da jede Zeile nur die Daten eines Feldes beinhalten kann. Eine simple Aufgabe die nicht so simpel lösbar ist.

Ich sehe euch SQL-Cracks schon mit wissender Miene schmunzeln, natürlich gibt es für das Problem in SQL eine Lösung, wie es ja wohl scheinbar fast immer eine gibt. Vorausgesetzt das Datenbanksystem unterstützt Subqueries lässt sich die Situation folgendermaßen bereinigen:

select *
from documents
where
id in 
(select docid from fields where fields.name='fieldname1' and fields.value='fieldvalue1') and
id in
(select docid from fields where fields.name='fieldname2' and fields.value='fieldvalue2')

Das ist der große Vorteil von SQL. Es ist eine derart alte, ausgereifte und umfangreiche Sprache dass es zu (fast) jedem Problem eine Lösung gibt. Nur: Das Verhältnis zwischen Komplexität der Anforderung und Komplexität der Lösung stimmt ganz und garnicht und es ist schwer zu definieren, was an Lösungen noch der Grundidee von SQL entspricht und was einem "Hack" gleichkommt.

Ich denke, jemand der schon so lange mit relationalen Systemen arbeitet dass er inzwischen in SQL "denkt" hat sich über die Zeit zwangsläufig eine recht hohe Schmerzgrenze erarbeitet was Abfragen-Komplexität angeht. Der hypothetische SQL-Crack wird sagen "Da hab ich aber schon wahrlich krudere Abfragen gesehen". Hat er wahrscheinlich auch. Wenn er jemals für Produktivsysteme mit nicht-trivialen Datenbanken zuständig war hatte er wohl keine andere Wahl.

Allen anderen muss zwangsläufig auffallen, dass die Verwendung komplexer hierarchischer Strukten in relationale Datenbanksystem spätestens mit SQL ihre Grenzen aufgezeigt bekommt.

Betrachten wir doch einmal eine vergleichbare XQuery-Abfrage gegen eine native XML-Datenbank. Nehmen wir folgende XML-Dokumentenstruktur an um unsere Daten zu speichern:

<document id="docid">
    <field name="fieldname1">fieldvalue1</field>
    <field name="fieldname2">fieldvalue2</field>
</document>

Angenehm fällt zunächst auf, dass wieder zusammen gespeichert wird was zusammen gehört, nämlich das gesamte Dokument inklusive Felder. Deren Verhältnis wird nicht mehr nur durch eine Foreign-Key-Beziehung zusammengehalten.

Jetzt formulieren wir SQL-Abfrage Numero 1 mal als XQuery-Version:

for $docs in /document
where
$docs/field[@name='fieldname1']='fieldvalue1'
return $docs

Abgesehen von der vielleichjt ungewohnten Struktur ist hier für jeden, der ein bisserl XPath-Kenntnisse besitzt, klar zu erkennen was gemacht wird. Der "for"-Bereich zieht alle Dokumente heran, die in die Wahl kommen (äquivalent zur SELECT-Klausel in SQL) und schiebt sie in die Variable "$docs". Der "where"-Bereich führt, ebenso wie in SQL, die Selektion aus indem er XPath-Ausdrücke mit Werten vergleicht.

Lediglich zunächst etwas abstrakt anmutend (aber irre praktisch) die "return"-Klausel welche aus den selektierten Variablen die Ausgabe formt. Hier wäre es noch möglich, aus dem Ergebnis einzelne Werte herauszupicken oder es sogar a'la XSLT zu transformieren. In diesem Beispiel begnügen wir uns jedoch mit der Ausgabe der Dokumente.

Wenig überraschend ist die XQuery-Variante der SQL-Abfrage Numero 2 "straight-forward" aus dieser Syntax abzuleiten:

for $docs in /document
where
$docs/field[@name='fieldname1']='fieldvalue1' and
$docs/field[@name='fieldname2']='fieldvalue12' and
return $docs

Keine Notwendigkeit für irgendwas so exotisches (und unperformantes) wie Subqueries. Wer die XQuery-Basissyntax einmal kennt wird diese Abfrage ohne grosses Nachdenken konstruieren können.

Fazit: In XML-Datenbanken kann ich tief geschachtelte Daten nicht nur besser ablegen, sie lassen sich auch entscheidend besser abfragen.

Bald mehr zu meinem XML-Datenbanksystem "of choice" und dem kleinen Projekt das in meinem Kopf herangärt.

Bitte geben Sie hier Ihren Kommentar ein:

Verwende Markdown Syntax

Autor

About

Last comments

  • Oliver:
    Als Antwort auf "Anonym" vom 27. Dezember 2015 (..
  • anonym:
    Habbo als abzocke zu deklarieren finde ich schon..
  • anonym:
    Wenn du es dir leisten kannst und es dich glückl..
  • Jebote:
    ja sicher kommen alle auf diesen 5 jahre alten a..
  • Micha:
    @Ingo, na klar. Alles legitim und voll ok ;-) Mu..

Really currently consuming

Links

  • Mehr Whisky
  • Ich@last.fm
  • Ich@Twitter
  • Dina
  • Julia
  • Der Meister (nebst Frau Meister)
  • Rockender Webworker
  • Irgendwas mit Fischen