Datenpunkte

Was zum Kuckuck sind Dokumentendatenbanken?

Julie Lerman

 

Julie LermanEs ist gut möglich, dass Sie zumindest bereits vom Begriff „NoSQL“ gehört haben. Im MSDN Magazin wurden sogar einige Artikel zu diesem Thema veröffentlicht. Viele Kollegen, die ich sehr schätze, sind ziemlich begeistert von Dokumentendatenbanken. Da ich mich vornehmlich mit relationalen Datenbanken beschäftige, wollte ich diese neuen Datenbanken besser verstehen. Ich habe ein bisschen nachgeforscht und meine Freunde inständig gebeten, mir Dokumentendatenbanken zu erklären. In diesem Artikel teile ich Ihnen nun mit, was ich über das Subset von NoSQL-Datenbanken, den sogenannten „Dokumentendatenbanken”, gelernt habe. Als weiteres Subset sind Schlüsselwert-Paardatenbanken zu nennen. Windows Azure-Tabellenspeicher, über die ich in meiner Rubrik „Datenpunkte“ im Juli 2010 (msdn.microsoft.com/magazine/ff796231) geschrieben habe, ist ein Beispiel für ein Schlüsselwertpaar des NoSQL-Speichers.

Ich möchte zuerst die Definition von NoSQL erläutern. Dieser Begriff wird mittlerweile universell und möglicherweise viel zu häufig verwendet. Er schließt Datenspeichermechanismen ein, die nicht relational sind und daher SQL nicht zum Zugriff auf die Daten benötigen. In seinem Blogbeitrag „Addressing the NoSQL Criticism“ (Ansprechen der Kritik zu NoSQL) (bit.ly/rkphh0) schreibt der CouchDB-Experte und Verfasser Bradley Holt, dass er von Leuten gehört hat, die „NoSQL als 'nicht nur SQL'“ neu definieren. Er steht auf dem Standpunkt, dass dies auf keinen Fall eine anti-SQL-Bewegung ist. Mir gefällt diese Perspektive, weil ich sehr viel davon halte, das richtige Tool für die Aufgabe einzusetzen.

Die meisten Datenbanken, die unter die Kategorie „nicht relational“ fallen, weisen gemeinsame Ziele hinsichtlich Geschwindigkeit und Skalierbarkeit auf. Wenn man sich vom relationalen Speichermodell löst und Schemata hinter sich lässt, haben diese Datenbanken keine Beschränkungen, die ihnen von eng gebundenen Schemata sowie von den Anforderungen Ihrer Anwendung, Daten über Tabellen hinweg zusammenzuführen, auferlegt werden.

Unter den zahlreichen verfügbaren Dokumentendatenbanken möchte ich mich auf die zwei der beliebtesten konzentrieren: MongoDB (mongodb.org) und CouchDB (couchdb.apache.org) sowie RavenDB (ravendb.net). Letztere wurde für Microsoft .NET Framework erstellt und erfreut sich wachsender Beliebtheit (lesen Sie auch den Artikel „Einbetten von RavenDB in eine ASP.NET MVC 3-Anwendung“ in dieser Ausgabe). Wir befinden uns weiterhin auf einer hohen Ebene, dennoch können Sie viele weitere Details über die einzelnen Datenbanken und ihre einzigartigen Unterschiede erfahren. Rufen Sie hierzu einfach die jeweiligen Websites auf.

Mit Ausnahme einiger überraschenden Wendungen (auf die ich in diesem Artikel eingehe), stellen diese Datenbanken ihre Daten häufig über HTTP bereit, speichern ihre Daten als JSON-Dokumente (JavaScript Object Notation) und bieten APIs in mehreren Sprachen an. Die Bedenken insgesamt drehen sich um Einfachheit, Geschwindigkeit und Skalierbarkeit. Genauso wichtig ist die Tatsache, dass es sich bei allen drei Datenbanken um Open Source-Projekte handelt.

Bei meinen Nachforschungen habe ich von einem MongoDB-Experten gehört, dass die Hauptsorge des Produkts bei der Leistung lag. Ein CouchDB-Experte wies auf die Einfachheit und Zuverlässigkeit hin („wir möchten der Honda Accord unter den Datenbanken sein“). Und Ayende Rahien, der Schöpfer von RavenDB, meinte, dass RavenDB auf „schnelle Schreib- und Lesevorgänge und Weltfrieden abzielt“. Jede dieser Dokumentendatenbanken hat weitaus mehr zu bieten, als diese prägnanten Namen nahelegen.

Eine Alternative und kein Ersatz für relationale Datenbanken

Die NoSQL- und Dokumentendatenbanken stellen eine Alternative für relationale Datenbanken dar und sind nicht als Ersatz anzusehen. Jede Datenbank hat ihren eigenen Speicherort und bietet Ihnen einfach mehr Optionen, aus denen Sie wählen können. Wie treffen Sie jedoch die Auswahl? Ein bedeutendes Maß ist das Theorem „Consistency, Availability and Partition Tolerance“ (CAP – Konsistenz, Verfügbarkeit und Partitionstoleranz). Es besagt, dass bei Arbeiten mit verteilten Systemen nur zwei der drei Konstanten garantiert sind (das C, das A oder das P), sodass Sie den für Sie wichtigen Wert auswählen müssen. Wenn „Consistency“ die größte Bedeutung hat, müssen Sie eine relationale Datenbank verwenden.

Ein allgemeines Beispiel, bei dem Konsistenz die wichtigste Konstante darstellt, ist eine Banking-Anwendung oder vielleicht eine Anwendung für eine nukleare Anlage. In diesen Szenarien ist es von großer Bedeutung, dass jedes einzelne Datenelement zu jedem Zeitpunkt berücksichtigt wird. Bei einer Abbuchung müssen Sie dies genau wissen, wenn Sie sich den Kontostand ansehen. Deshalb sollten Sie möglicherweise eine relationale Datenbank mit einem hohen Maß an Kontrolle über ihre Transaktionen einsetzen. Ein Begriff, der Ihnen häufig zu Ohren kommt, ist „Eventual Consistency“, oder wie auf der RavenDB-Website ausgedrückt wird: „Besser ausgelutscht als offline.“ In anderen Domänen ist „Eventual Consistency“ ausreichend. Es ist völlig in Ordnung, wenn die abgerufenen Daten nicht bis auf die allerletzte Sekunde genau sind.

Eventuell ist es dann wichtiger, dass einige Varianten der Daten verfügbar sind, als darauf zu warten, dass alle Transaktionen auf den neuesten Stand kommen. Dies gilt für das A (Availability) in CAP und bezieht sich auf die Serverbetriebszeit. Die Tatsache, dass Sie stets Zugriff auf die Datenbank haben, hat Vorrang und ist ein enormer Vorteil für die Datenbankleistung (Dokumentendatenbanken sind schnell!). Sie werden auch feststellen, dass das P in „Partition Tolerance“ ebenfalls ein bedeutender Faktor für Dokumentendatenbanken ist, besonders bei horizontaler Skalierung.

RESTful HTTP-API – Meistens

Viele der NoSQL-Datenbanken können mit einer RESTful-Methode abgerufen werden, sodass Sie Ihre Datenbankverbindung über ein URI herstellen. Bei den Abfragen und Befehlen handelt es sich um HTTP-Aufrufe. MongoDB stellt eine Ausnahme dar. Standardmäßig wird hier TCP für Datenbankinteraktionen verwendet, obwohl auch mindestens eine HTTP-API verfügbar ist. CouchDB und MongoDB bieten sprachspezifische APIs, mit denen Sie Abfragen und Updates schreiben und ausführen können, ohne sich Gedanken über das direkte Schreiben von HTTP-Aufrufen machen zu müssen. RavenDB besitzt eine .NET-Client-API, die Interaktionen mit der Datenbank vereinfacht.

Zugehörige Daten in einem einzelnen Datensatz

Viele Leute nehmen fälschlicherweise an, dass es sich bei nicht relationalen Datenbanken um Flatfiles handelt. Die in einer Dokumentendatenbank gespeicherten Dokumente können geformte Daten enthalten: Strukturen mit Knoten. Jeder Datensatz in der Datenbank ist ein Dokument und kann ein autonomer Satz von Daten sein. Er ist selbsterklärend – einschließlich seines möglichen eindeutigen Schemas – und hängt nicht unbedingt von anderen Dokumenten ab.

Im Folgenden ist ein typisches Beispiel eines Datensatzes in einer Dokumentendatenbank angegeben (dieser Ausschnitt stammt vom MongoDB-Lernprogramm, das einen Studenten darstellt):

{
  "name" : "Jim",
  "scores" : [ 75, 99, 87.2 ]
}

Und hier ist ein Beispiel aus dem CouchDB-Einführungsartikel, das ein Buch beschreibt:

{
  "Subject": "I like Plankton"  
  "Author": "Rusty"  
  "PostedDate": "5/23/2006"  
  "Tags": ["plankton", "baseball", "decisions"]
  "Body": "I decided today that I don't like baseball. I like plankton."
}

Dies sind einfache Strukturen mit Zeichenfolgedaten, Zahlen und Arrays. Für eine komplexere Dokumentstruktur können Sie Objekte auch innerhalb von Objekten einbetten, wie dieses Beispiel eines Blogbeitrags zeigt: 

{
  "BlogPostTitle”: “LINQ Queries and RavenDB”,
  "Date":"\/Date(1266953391687+0200)\/",
  "Content":”Querying RavenDB is very familiar for .NET developers who are already
    using LINQ for other purposes”,
  "Comments":[
             {
             "CommentorName":"Julie",
             "Date":"\/Date(1266952919510+0200)\/",
             "Text":"Thanks for using something I already know how to
               work with!",
             "UserId":"users/203907"             
             },
  ]
}

Eindeutige Schlüssel

Alle Datenbanken erfordern einen Schlüssel. Wenn Sie keinen angeben, wird einer für Sie intern erstellt. Schlüssel sind zum Indizieren von Datenbanken unerlässlich, Ihre eigene Domäne erfordert jedoch unter Umständen bekannte Schlüssel. Im vorherigen Beispiel des Blogbeitrags gibt es einen Verweis auf „users/203907“. Dies zeigt an, wie RavenDB Schlüsselwerte nutzt und Sie Beziehungen zwischen Dokumenten definieren können.

Speicherung im JSON-Format

Diese Beispieldatensätze haben eins gemeinsam: Sie verwenden alle JSON zum Speichern von Daten. CouchDB und RavenDB (sowie viele andere Datenbanken) speichern ihre Daten in der Tat im JSON-Format. MongoDB verwendet ein etwas abgeändertes Format von JSON, und zwar Binary JSON (BSON), mit dem eine binäre Serialisierung durchgeführt werden kann. BSON ist die interne Darstellung der Daten, sodass Sie hinsichtlich der Programmierung keine Unterschiede feststellen sollten.

Dank der Einfachheit von JSON können Objektstrukturen von nahezu jeder Sprache kinderleicht in JSON umgesetzt werden. Daher können Sie Ihre Objekte in Ihrer Anwendung definieren und direkt in der Datenbank speichern. Hierdurch müssen Entwickler nicht mehr eine objektrelationale Zuordnung (Object-Relational Mapping, ORM) verwenden, um ständig zwischen dem Datenbankschema und dem Klassen-/Objektschema zu übersetzen.

Volltextsuchmaschinen wie Lucene (lucene.apache.org), auf das sich RavenDB stützt, bieten leistungsstarke Suchvorgänge für diese textbasierten Daten.

Beachten Sie das Datum im Beispiel des Blogbeitrags. JSON hat keinen Datentyp, jedoch bietet jede Datenbank eine Methode zur Interpretation der Datentypen in einer beliebigen Programmiersprache, in der Sie sie kodieren. Wenn Sie sich die Liste der Datentypen und Konventionen für die MongoDB BSON-API (bit.ly/o87Gnx) ansehen, werden Sie feststellen, dass ein Datentyp zusammen mit einigen anderen Elementen hinzugefügt wurde, um die verfügbaren Möglichkeiten in JSON zu untermauern.

Die Speicherung und der Abruf von zugehörigen Daten in einer einzelnen Einheit können erhebliche Vorteile hinsichtlich Leistung und Skalierbarkeit bieten. Datenbanken müssen keine Umwege gehen, um Daten zu suchen, die im Allgemeinen verwandt sind, da alles an einer Stelle zusammengefasst ist.

Typensammlungen

Wie weiß Ihre Anwendung bei Interaktionen mit der Datenbank, dass ein Element ein Student, ein anderes Element ein Buch und ein weiteres Element ein Blogbeitrag ist? Die Datenbanken nutzen hierzu Sammlungen. Jedes Dokument – ungeachtet seines Schemas, das mit einer bestimmten Sammlung verbunden ist (zum Beispiel mit der Sammlung „Student“) – kann beim Anfordern von Daten aus dieser Sammlung abgerufen werden. Es ist auch nicht ungewöhnlich, ein Feld zur Angabe des Typs zu verwenden. Hierdurch werden Suchvorgänge um ein Vielfaches einfacher, es liegt jedoch an Ihrer Anwendung, zu erzwingen, welche Datentypen in einer Sammlung einbezogen werden sollten und welche nicht.

Datenbanken mit weniger Schemata

Die vorher beschriebene Sammlung „Student“ verfügt über ihr eigenes Schema. Jeder Datensatz ist für sein eigenes Schema verantwortlich, auch für solche Schemata, die in einer einzelnen Datenbank oder Sammlung enthalten sind. Ein Student-Datensatz muss nicht unbedingt mit einem anderen Student-Datensatz übereinstimmen. Natürlich muss Ihre Software in der Lage sein, alle Unterschiede zu erkennen und zu berücksichtigen. Sie könnten einfach diese Flexibilität für Effizienz nutzen. Warum sollten Sie beispielsweise Nullwerte speichern? Sie könnten zum Beispiel wie folgt vorgehen, wenn eine Eigenschaft wie „most_repeated class“ keinen Wert hat:

"name" : "Jim",
"scores" : [ 75, 99, 87.2 ]
"name" : "Julie",
"scores" : [ 50, 40, 65 ],
"most_repeated_class" : "Time Management 101"

Ja, Virginia, wir unterstützen Transaktionen

Alle Datenbanken bieten ein gewisses Maß an Transaktionsunterstützung, einige mehr als andere, aber keine bietet so umfassende Möglichkeiten wie eine relationale Datenbank. Ich gehe auf die jeweilige Dokumentation ein und lasse Sie Ihre eigenen zusätzlichen Forschungen anstellen.

Dokumentendatenbanken und domänengesteuerte Entwicklung

Eins der grundlegenden Konzepte von domänengesteuerter Entwicklung bezieht sich auf die Gestaltung Ihrer Domäne mithilfe von Aggregatstämmen. Bei der Planung Ihrer Domänenklassen (die in Ihrer Datenbank unter Umständen zu Dokumenten werden) können Sie Daten suchen, die sehr häufig eigenständig sind (zum Beispiel eine Bestellung mit aufgeführten Posten), und sich auf dieses als individuelle Datenstruktur konzentrieren. In einem Bestellsystem werden möglicherweise auch Kunden und Produkte angegeben. Auf eine Bestellung kann jedoch ohne erforderliche Kundendaten zugegriffen werden, und ein Produkt kann verwendet werden, ohne dass die Bestellungen abgerufen werden müssen, in denen es enthalten ist. Obwohl es viele Möglichkeiten für eigenständige Datenstrukturen gibt (wie die Bestellung mit aufgeführten Posten), bedeutet dies nicht unbedingt, dass die Notwendigkeit oder Fähigkeit entfällt, Daten über Fremdschlüssel in bestimmten Szenarien zusammenzuführen.

Alle Datenbanken bieten eine Anleitung für verschiedene Muster, die verfügbar sind und mit welchen die Benutzer die größten Erfolge verbuchen können. Die MongoDB-Dokumentation erwähnt zum Beispiel das Muster „Array of Ancestors“, das den Zugriff auf zugehörige Daten beim Zusammenführen von Dokumenten beschleunigt.

Bedenken hinsichtlich des Navigierens in Beziehungen sind an die Tatsache gebunden, dass das Wiederholen von Daten in einer relationalen Datenbank ein Frevel ist. Datenbanken sind normalisiert, um dies zu gewährleisten. Beim Arbeiten mit NoSQL-Datenbanken, besonders mit verteilten Datenbanken, ist das Denormalisieren von Daten sowohl nützlich als auch zulässig.

Abfragen und Aktualisieren

Jede Datenbank verfügt standardmäßig über APIs für Abfragen und Aktualisierungen. Obwohl sie möglicherweise nicht Teil der Kern-API sind, werden zahlreiche Sprach-APIs über Add-Ons bereitgestellt. Als ein .NET Framework-Eintrittspunkt in die Welt der Dokumentendatenbanken nutzt RavenDB LINQ für Abfragen – ein toller Vorteil für .NET-Entwickler.

Andere Abfragen hängen von vordefinierten Ansichten und einem Muster mit der Bezeichnung „map/reduce“ ab. Der Map-Teil dieses Prozesses verwendet die Ansichten, und die Verantwortlichkeit der Zuordnung unterscheidet sich je nach Datenbank. „Map“ ermöglicht der Datenbank auch die Verteilung der Abfrageverarbeitung über mehrere Prozessoren hinweg. „Reduce“ nimmt das Ergebnis der Map-Abfrage (bzw. Abfragen, falls sie verteilt wurden) und aggregiert Daten in die Ergebnisse, damit sie an den Client zurückgegeben werden können.

„Map/reduce“ ist ein Muster, und die verschiedenen Datenbanken haben ihre eigenen Implementierungen. Rob Ashton stellt unter bit.ly/94OCME einen interessanten Vergleich an, wie RavenDB und CouchDB den Prozess „map/reduce“ durchführen.

Während CouchDB erfordert, dass die Abfrage über die vordefinierte map/reduce-Ansicht erfolgt, bietet MongoDB (auch mithilfe von Ansichten und „map/reduce“) zusätzlich die Möglichkeit, Ad-hoc-Abfragen durchzuführen. RavenDB ermöglicht nicht nur vordefinierte Indexe für Abfragen, sondern unterstützt auch Ad-hoc-Abfragen. Indexe werden basierend auf Ihren tatsächlichen Laufzeitabfragen automatisch für Sie erstellt. Wenn Sie sich von den bekannten Schemata und der relationalen Art der SQL-Datenbanken verabschieden, ist in der Regel die Möglichkeit zur Durchführung von Ad-hoc-Abfragen eines des Features, das Sie verlieren. Mit einer engen Kontrolle über die Abfrage können die Dokumentendatenbanken ihr Versprechen hinsichtlich schneller Leistung einhalten.

Eine Datenbankrevolution

Es gibt unglaublich viele nicht relationale Datenbanken in der NoSQL-Kategorie. Da nun die ersten Schritte gemacht wurden, wird es mehr Aufregendes geben, weil Leute sich alle verfügbaren Datenbanken ansehen und davon träumen, wie sie diese verbessern können. Ich denke, dass RavenDB ein großartiges Beispiel hierfür ist, und Sie Zeuge werden können, wie Rahien die Datenbank weiter entwickelt, da er weiterhin davon träumt, wie er diese verbessern oder sich von Benutzern inspirieren lassen kann.

Ich glaube auch, dass das Interesse über diese Datenbanken ansteckend ist. Ich freue mich auf jeden Fall darauf, weiter nachzuforschen und mehr zu erfahren. Aber auch wenn die drei Datenbanken, die ich näher erläutert habe, so interessant sind, ist es schwer für mich als Sternzeichen Waage, eine Auswahl unter diesen zu treffen, da ich momentan nur meine Neugier befriedige und nicht unbedingt ein echtes Geschäftsproblem löse. Relationale Datenbanken sind genau die richtige Lösung für meine aktuellen Projekte.

Julie Lerman ist Microsoft MVP, .NET-Mentor und Unternehmensberaterin und lebt in den Bergen von Vermont. Sie hält bei User Groups und Konferenzen in der ganzen Welt Vorträge zum Thema Datenzugriff und anderen Microsoft .NET-Themen. Julie Lerman führt einen Blog unter thedatafarm.com/blog und ist Autorin des ausgezeichnet bewerteten Buchs „Programming Entity Framework“ (Programmieren des Entity Framework) (O’Reilly Media 2010). Folgen Sie ihr auf Twitter unter twitter.com/julielerman.

Unser Dank gilt den folgenden technischen Experten für das Lektorat dieses Artikels: Ted Neward und Savas Parastatidis.