© rossphoto/Shutterstock.com
Daten schemafrei mit Hibernate in PostgreSQL speichern

Schnell und flexibel …


Dieser Artikel zeigt, wie Daten schemafrei mit dem relationalen Datenbanksystem PostgreSQL abgespeichert und effizient abgefragt werden können. Darüber hinaus wird aufgezeigt, wie eine Integration in JPA respektive Hibernate gelingt.

Fast jede Anwendung hat die Anforderung, Daten dauerhaft zu speichern und performant abzufragen. Für diesen Zweck wurden Datenbanken entwickelt. Neben den relationalen Datenbanken mit der Abfragesprache SQL als Platzhirsch haben sich mittlerweile weitere, sogenannte NoSQL-Datenbanken (z. B. Document Stores, Key-Value Stores, Graphdatenbanken) etabliert.

Relationale Datenbanken speichern Daten üblicherweise in festen Schemata, wohingegen Document Stores hier flexibler sind. Es kommt in Anwendungen häufig vor, dass ein Großteil der zu speichernden Daten einem festen Schema folgt, aber zumindest bei einem Teil der Daten die Struktur variiert.

Eine viel bemühte Beispielanwendung

Als leicht verständliches Beispiel soll an dieser Stelle die Produkttabelle eines E-Commerce-Systems bemüht werden. Jedes Produkt in dieser Tabelle hat immer eine Artikelnummer, hier als SKU (Stock Keeping Unit) bezeichnet, einen Namen und einen Preis. Es gibt allerdings Attribute, die nur für spezielle Produktkategorien interessant sind: Zum Beispiel spielen bei einem Toaster die Farbe und das Gewicht eine Rolle. Für digitale Güter, die im gleichen Shop verkauft werden, sind diese Eigenschaften allerdings völlig uninteressant. Ein Produkt könnte also wie in Listing 1 in JSON modelliert sein.

Listing 1: Modellierung von Produktdaten

{ "name": "Brown Toast 4000", "sku": "A-12345678", "price": { "currency": "EUR", "value": 20.00 }, "attributes": { "colors": ["green", "black"], "weight": { "unit": "g", "value": 1250 }, "measures": { "unit": "mm", "height": 250, "width": 400, "depth": 250 } } }

Die Felder name, sku und price sind definitiv für jedes Produkt vorhanden. Die Objekte unter dem Schlüssel attributes können für jedes Produkt verschieden sein.

Es ist nicht sinnvoll, in einem relationalen Datenbankschema alle möglichen Produktattribute vorauszuahnen und jedem jeweils eine eigene Spalte in der Produkttabelle zu spendieren. Alternativ könnte zur Produkttabelle eine weitere Tabelle gepflegt werden, in der jeweils in einer eigenen Zeile ein Produktattribut zu einem Produkt gespeichert wird. Die Beziehung zwischen Produktattributtabelle und Produkttabelle würde dann durch einen Fremdschlüssel hergestellt. Beim Abrufen eines einzelnen Produkts müssten alle Einträge in der Produktattributtabelle für dieses Produkt durch einen Join abgerufen werden. Dieses Vorgehen wäre der Performanz der Anwendung sicherlich nicht zuträglich. Der eben beschriebene Modellierungsansatz wird auch als Entity-Attribute-Value Model [1] bezeichnet. Alternativ bietet sich natürlich immer noch die Nutzung eines Document Stores als Datenbanklösung an, der es erlaubt, Daten ohne Schema abzuspeichern. Dafür fehlen häufig viele liebgewonnene Funktionalitäten von relationalen Datenbanken, zum Beispiel Transaktionen oder die Möglichkeit, eine effiziente Abfragesprache zu nutzen.

Daten schemafrei in PostgreSQL speichern

Viele relationale Datenbanken bieten mittlerweile die Möglichkeit, Daten innerhalb einer separaten Spalte schemafrei zu speichern, zum Beispiel im JSON-Format. So bietet PostgreSQL bereits seit Version 9.2 (veröffentlicht im September 2012) die Datentypen JSON und JSONB an, um Daten schemafrei darin zu speichern [2]. Für die Praxis relevant ist hier eigentlich nur der Datentyp JSONB. Die Daten im JSON-Format werden in Feldern dieses Datentyps in einem binären Format gespeichert und nehmen daher weniger Platz ein. Auch können die gespeicherten Daten in Indizes genutzt werden [3].

Wenn die vorher besprochene Produktdatenbank mit PostgreSQL modelliert wird, dann könnte die Tabelle so aussehen wie in Listing 2.

Listing 2: Definition Produkttabelle

CREATE TABLE product ( id BIGSERIAL NOT NULL PRIMARY KEY , name VARCHAR(255) NOT NULL, sku VARCHAR(255) NOT NULL UNIQUE, price DECIMAL(10,2) NOT NULL, currency VARCHAR(5) NOT NULL, attributes JSONB );

Alle variablen Daten werden im Feld attributes gespeichert. Die anderen Spalten der Tabelle werden ab hier nicht weiter betrachtet.

Schnell auf Daten zugreifen

Ab jetzt könnten schon Daten in die Produkttabelle und das Feld attributes eingetragen werden. Wenn allerdings nach allen Produkten mit der Farbe green gesucht werden soll, müsste für die Abfrage ein Full Table Scan durchgeführt werden, um alle Produkte mit dieser Farbe zu finden. Das bedeutet, dass jeder einzelne Eintrag in der Produkttabelle durchsucht werden muss. Um dies zu vermeiden, kann auf Feldern des Typs JSONB ein sogenannter GIN-Index angelegt werden. Das hat aber nichts mit Alkohol auf Basis von Wacholder zu tun, sondern steht für Generalized Inverted Index [4]. Dieser Index indiziert alle Schlüssel...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang