Für mein nächstes Websitedesign suche ich momentan unter anderem nach dem richtigen Datenmodell. Das ist deshalb nicht ganz einfach, weil mir sowohl das relationale als auch das „document-store“-artige zusagen, wenn auch jeweils aus verschiedenen Gründen. Sowohl die eine wie auch die andere Wahl wäre jeweils gut zu rechtfertigen. Einerseits werden viele der Daten nämlich immer gleicher Art sein: Artikel mit Veröffentlichungsdatum und Urheber, Kommentare, verschiedene Sprachversionen zu jedem Artikel. Andererseits gibt es sicherlich auch Ad-hoc-Daten, die entweder nur selten auftreten, oder derer ich mir zu Anfang noch gar nicht bewußt sein kann.

Die Wahl fällt also nicht leicht. Wäre es nicht schön, gäbe es ein relationales Datenbanksystem, das auch Ad-hoc-Daten sinnvoll modellieren und abfragen kann — jedenfalls, wenn man auf die leichte Skalierung, die „richtige“ NoSQL-Systeme bieten, verzichten kann?

Interessanterweise tut PostgreSQL das. Es gibt ein Modul namens „hstore“, das es ermöglicht, einfache Schlüssel-Wert-Paare in eine Extraspalte einer Tabelle zu legen. Das ist nun zunächst nichts Besonderes — man könnte auch ohne spezielle Unterstützung durch das Datenbanksystem auf die Idee kommen, beispielsweise zusätzliche JSON-Daten in eine eigens dafür vorgesehene Spalte abzulegen. hstore erlaubt es aber auch, die Daten in Queries zu verarbeiten und abzufragen:

=> CREATE TABLE people (id   SERIAL PRIMARY KEY,
                        name TEXT,
                        info HSTORE);
=> INSERT INTO people(name, info)
     VALUES ('Heinrich',
             hstore(ARRAY['age', '25',
                          'hobbies', '{science,chemistry,math}',
                          'town', 'Munoca']));
=> INSERT INTO people(name, info)
     VALUES ('Andrius',
             hstore(ARRAY['age', '24',
                          'hobbies', '{magic,science,languages}']));
=> INSERT INTO people(name, info)
     VALUES ('Nathalie',
             hstore(ARRAY['age', '22',
                          'favorite_meal', 'Schlutzkrapfen']));
=> SELECT * FROM people;
 id |   name   |                                 info                           
----+----------+----------------------------------------------------------------------
  1 | Heinrich | "age"=>"25", "town"=>"Munoca", "hobbies"=>"{science,chemistry,math}"
  2 | Andrius  | "age"=>"24", "hobbies"=>"{magic,science,languages}"
  3 | Nathalie | "age"=>"22", "favorite_meal"=>"Schlutzkrapfen"
(3 rows)
=> SELECT name FROM people WHERE (info->'age')::INTEGER < 25;
   name   
----------
 Andrius
 Nathalie
(2 rows)
=> SELECT name FROM people WHERE 'chemistry' = ANY ((info->'hobbies')::TEXT[]);
   name   
----------
 Heinrich
(1 row)

Wie man sieht, besteht ein Nachteil von hstore gegenüber JSON oder ähnlichem darin, daß alle Daten untypisiert als Zeichenketten gespeichert werden müssen. Da man solche in SQL in fast alles Erdenkliche casten kann, hat man dagegen ein Mittel zur Verfügung, schöner wäre eine irgendwie geartete Typisierung der Daten aber natürlich trotzdem.

Eine spätere Version von PostgreSQL (9.1?) könnte da zumindest etwas Abhilfe schaffen: Wie man hört, soll JSON in Zukunft nativ unterstützt werden.

Wenn man ein bißchen herumspielen möchte, kann man Views verwenden, um aus den im hstore gespeicherten Daten tabellarische zu machen:

=> CREATE OR REPLACE VIEW people2 AS
     SELECT id,
            name,
            (info->'age')::INTEGER AS age,
            info->'town'           AS town 
       FROM people;
=> CREATE OR REPLACE VIEW hobbies AS
     SELECT id, unnest((info->'hobbies')::TEXT[]) AS hobby
       FROM people;
=gt; SELECT * FROM people2;
 id |   name   | age |  town  
----+----------+-----+--------
  1 | Heinrich |  25 | Munoca
  2 | Andrius  |  24 | 
  3 | Nathalie |  22 | 
(3 rows)
=> SELECT name, hobby FROM people2, hobbies WHERE people2.id = hobbies.id;
   name   |   hobby   
----------+-----------
 Heinrich | science
 Heinrich | chemistry
 Heinrich | math
 Andrius  | magic
 Andrius  | science
 Andrius  | languages
(6 rows)

In dem Fall bekommt man die Typisierung und angenehme Syntax wieder zurück. Dafür hätte man die Daten hier auch gleich tabellarisch speichern können; allerdings handelt es sich bei dem Beispiel freilich um ein didaktisches. In der Praxis können tabellarische Views in Ad-hoc-Daten sich durchaus als nützlich erweisen, besonders wenn eine Abwärtskompatibilität des Datenbankschemas gewährleistet werden muß oder eine schrittweise Umstellung der Ad-hoc- auf tabellarische Daten geschehen soll.