In Folge 9 von „O wie Datenbank“ habe ich Johannes erklärt, wie JSON in die Oracle-Datenbank kommt: von der VARCHAR2-Spalte über BLOB statt CLOB bis zum nativen Datentyp JSON, der intern im Format OSON speichert. Auf die Frage, wie offen dieses Format eigentlich ist, musste ich damals ausweichen: Der Aufbau war nachlesbar, aber nur, wer sich durch den Quellcode der Thin Driver für Python und Node.js wühlte, bekam ihn zu sehen. Eine Spezifikation gab es nicht.
Das hat sich geändert. Oracle hat OSON als eigenständige Spezifikation veröffentlicht, nachzulesen unter osonspec.org. Version 1.0 beschreibt das komplette Wire-Format, dazu gibt es eine Java-Referenzimplementierung auf GitHub unter github.com/oracle/oson, lizenziert unter der Universal Permissive License. Damit ist OSON das, was BSON für MongoDB und JSONB für PostgreSQL längst sind: ein dokumentiertes Format, das jeder unabhängig implementieren kann.
Aufbau des Formats
OSON steht für Oracle Binary JSON und ist eine binäre Baumkodierung für JSON-Dokumente. Ein OSON-Wert besteht aus drei Teilen: einem Root-Header mit Magic Bytes, Version und Flags, einem Feldnamen-Wörterbuch und einem Segment mit den eigentlichen Baumknoten. Genau dieses Wörterbuch ist der Kern der Idee, die ich im Podcast mit „Keys nach oben ziehen“ umschrieben habe: Jeder Feldname wird pro Dokument nur einmal gespeichert und in den Knoten über eine kleine Feld-ID referenziert. Bei einem Array mit tausend Objekten, die alle dieselben zehn Attribute haben, macht das den Unterschied zwischen tausendfach wiederholten Schlüsseln und zehn Einträgen im Wörterbuch.
Der zweite Kernpunkt ist die Navigation. Container-Knoten speichern die Offsets ihrer Kinder, ein Decoder springt also direkt zu einem gesuchten Feld oder Array-Element, ohne das Dokument von vorn zu parsen. Deshalb ist JSON_VALUE auf einer JSON-Spalte schnell, obwohl das Dokument nie in Text zurückverwandelt wird. Die Spec stellt diesen Punkt selbst BSON gegenüber: Dort liegen Feldnamen inline bei jedem Element und die Traversierung läuft weitgehend sequenziell, bei OSON erlauben die Baum-Offsets einen direkten Sprung.
Dritter Punkt, und der ist für Datenbankleute interessanter als für Web-Entwickler: Partial Update. Die Formatversionen 0x02 und 0x04 erlauben es, ein Dokument in-place zu ändern, ohne es komplett neu zu schreiben. Dafür gibt es Forwarding-Records und Overflow-Segmente, die ein Reader beim Navigieren auflösen muss. Wer schon einmal ein JSON_TRANSFORM auf einem großen Dokument abgesetzt und sich gewundert hat, dass das Redo-Volumen überschaubar blieb, findet hier die Erklärung.
Und schließlich die SQL-Skalare. JSON kennt Strings, Zahlen, Booleans und null. OSON kennt zusätzlich DATE, TIMESTAMP mit und ohne Zeitzone, INTERVAL, BINARY_FLOAT, BINARY_DOUBLE, native 32- und 64-Bit-Integer, Decimal128, IDs wie UUID und ObjectId und als erweiterten Binärtyp auch Vektor-Embeddings. Das Format trägt damit genau die Typen, die man braucht, sobald JSON in einer relationalen Datenbank gespeichert und abgefragt wird.
Konsequenzen für Architektur und Betrieb
Für den Alltag als DBA oder Entwickler ändert sich zunächst nichts. Der Datentyp JSON bleibt Teil der Oracle-Datenbank, und die Spec macht ihn nicht zu Open Source. Offen ist das Format; die Engine bleibt proprietär. Genau diese Trennung ist für Architekturentscheidungen relevant.
Erstens Interoperabilität. Bisher konnten nur Oracles eigene Treiber OSON erzeugen und lesen. Mit einer öffentlichen Spec und einer Referenzimplementierung kann jede Sprache und jedes Werkzeug OSON nativ verarbeiten, ohne den Umweg über Text. Die Spec benennt sogar die typischen Stolperstellen für Fremdimplementierungen, etwa die Byte-Reihenfolge des Wörterbuch-Hashes und die Sortierung der Feld-IDs.
Zweitens Transparenz. Wer bislang wissen wollte, warum ein JSON-Dokument in der Datenbank so groß oder so klein ist, wie es ist, musste raten oder den Treiber-Code lesen. Jetzt steht es mit Opcode-Tabellen und Beispielen in einem Dokument, das man einem Kollegen schicken kann.
Drittens Bestandsschutz. Ein dokumentiertes Format mit Versionierungsregeln und Konformitätsanforderungen ist etwas, worauf man ein Datenmodell bauen kann. Die Spec legt fest, dass Reader die Versionen 0x01 bis 0x04 akzeptieren müssen, unbekannte Versionen ablehnen und Offsets vor dem Dereferenzieren prüfen. Das ist die Sprache, in der man über langlebige Datenformate spricht.
Nachtrag zur Podcast-Folge
Die Shownotes zu Folge 9 „Oracle und JSON: Vom CLOB über den nativen Datentyp zu Duality Views“ haben wir um die Links zur Spec und zur Referenzimplementierung ergänzt. Die Aussage aus der Folge, OSON sei über die Thin Driver quelloffen, war zum Aufnahmezeitpunkt korrekt und ist jetzt schlicht überholt: Es gibt die offizielle Spezifikation.
Wer tiefer einsteigen will, findet in der Spec auch die beiden wissenschaftlichen Arbeiten, auf denen das Format beruht, das SIGMOD-Paper von 2016 und das VLDB-Paper von 2020 zum nativen JSON-Datentyp. Und wer nachrechnen möchte, ob OSON in der eigenen Anwendung wirklich kleiner und schneller ist als BSON: Die Referenzimplementierung ist ein Maven-Projekt, ein JDK 11 reicht.
Links
- OSON Specification 1.0: osonspec.org
- Referenzimplementierung (Java, UPL): github.com/oracle/oson
- Podcast-Folge 9: Oracle und JSON: Vom CLOB über den nativen Datentyp zu Duality Views
- Oracle JSON Developer’s Guide (26ai): docs.oracle.com
