Postgres 19: Standard-Kompression wechselt von pglz zu LZ4

Deine Reaktion:

Eine E-Mail-Anlage wird manchmal zu groß und muss komprimiert werden. Datenbanken haben das gleiche Problem bei großen Textfeldern. PostgreSQL steht seit den ersten Versionen mit einem 8-Kilobyte-Limit pro Zeile vor dieser Herausforderung. Mehr als zwei Jahrzehnte später plant das Kernteam eine grundlegende Änderung: Der Standard-Komprimierungsalgorithmus für TOAST (The Oversized-Attribute Storage Technique) wechselt von pglz auf LZ4. Das klingt technisch, hat aber direkte Auswirkungen auf die Performance deiner Datenbank.

Wie PostgreSQL Daten komprimiert

PostgreSQL verwendet ein einheitliches Komprimierungs-Framework für Heap-Tabellen, TOAST und Indizes. Bei Heap und TOAST läuft die Komprimierung automatisch und ist standardmäßig aktiviert – für alle variablen Datentypen wie TEXT, VARCHAR, BYTEA und JSONB. Bei Indizes ist die Komprimierung opportunistisch: Sie greift nur, wenn ein einzelner Schlüssel eine bestimmte Größenschwelle überschreitet. Das vereinfacht die Architektur. Müsste jedes Datenbankmodul eigenen Komprimierungs-Code schreiben, wäre die Wartung ein Albtraum. Stattdessen teilen sich alle Komponenten denselben Mechanismus.

Die Geschichte: Vom Workaround zur Standardlösung

Die erste Komprimierung in PostgreSQL kam mit Version 7.0 im Jahr 2000 – in einer ganz anderen Form. Damals gab es ein striktes Limit von 8 kB pro Zeile. Wer mehr Daten einfügen wollte, bekam einen Fehler. Die Entwickler versuchten zuerst, das Problem mit einem explizit komprimierten Datentyp namens lztext zu lösen. Das war ein Fortschritt, aber die 8-kB-Grenze blieb bestehen, und Anwender mussten sich bewusst für einen speziellen Typ entscheiden. Der nächste logische Schritt wäre gewesen, weitere komprimierte Typen einzuführen – so wie es viele kommerzielle Datenbanken taten. Das PostgreSQL-Kernteam wählte einen anderen Weg. In Diskussionen auf der pgsql-hackers-Mailingliste spalteten sie das Problem in zwei Teile: ein Datentyp-Problem und ein physisches Speicherproblem. Für Letzteres entwickelten sie TOAST in Version 7.1 – zusammen mit dem hauseigenen Algorithmus pglz.

pglz wurde von Jan Wieck geschrieben und basiert auf einer Idee von Adisak Pochanayon, die ursprünglich für die Spieleindustrie gedacht war – zur Komprimierung von Grafiken und Audiodaten. Die Prioritäten waren klar: Geschwindigkeit vor Kompressionsrate, minimaler Speicherverbrauch (ein 4096-Byte-Schiebefenster) und aggressives Frühabbruchverhalten bei inkompressiblen Daten. Außerdem brauchte PostgreSQL keine externen Abhängigkeiten. Damals – vor der Cloud-Ära – musste PostgreSQL auf jeder Plattform laufen, ohne auf Bibliotheken wie zlib angewiesen zu sein. pglz war ein pragmatischer, solider Kompromiss. Die Zeiten haben sich geändert.

Warum LZ4 den Platz von pglz einnimmt

LZ4 ist ein moderner Algorithmus, dessen Trade-offs zu heutiger Hardware passen. Seit PostgreSQL 14 kann man LZ4 systemweit (default_toast_compression = 'lz4') oder spaltenspezifisch (column TEXT COMPRESSION lz4) aktivieren. Jetzt wird es zum Standard. Der Vorteil liegt in der Geschwindigkeit. In einem Test mit 2000 INSERTs von je ~10 kB großen Werten brauchte LZ4 nur 6 Millisekunden, pglz dagegen 50 Millisekunden – etwa achtmal schneller. Die Dekomprimierung ist bei beiden ähnlich schnell, weil hier die I/O- und Speicherlatenz dominiert. Auch das Kompressionsverhältnis kann besser sein: LZ4s 64-kB-Schiebefenster findet mehr Back-References als pglz mit seinen 4 kB. Im Test ergab LZ4 111 Bytes gespeichert pro 10.400 Bytes Rohdaten (98,9 % Reduktion) gegenüber 186 Bytes bei pglz (98,2 % Reduktion). Der gesamte Heap-Speicher sank von 472 kB auf 312 kB. In seltenen Fällen komprimiert pglz noch besser. LZ4 hat ebenfalls einen effizienten Frühabbruch, um bei Zufallsdaten keine CPU zu verschwenden.

Diese Änderung folgt demselben Muster wie der ursprüngliche pglz-Rollout: zuerst als Option, dann als Standard. Das Kernteam hat die Algorithmen jahrelang parallel getestet und sich nun für den Wechsel entschieden.

Die Speicherstrategien im Detail

PostgreSQL kennt vier Speicherstrategien für Spalten. EXTENDED (großgeschrieben wie in der Dokumentation) ist der Standard für variable Typen. Hier darf PostgreSQL alle Werkzeuge nutzen: Speicherung unkomprimiert, komprimiert, im Heap oder in TOAST. PLAIN speichert die Spalte inline und unkomprimiert – der Default für fixe Typen wie INT, FLOAT, BOOL. EXTERNAL zwingt die Spalte in die TOAST-Tabelle, aber ohne Komprimierung. MAIN versucht zu komprimieren, aber die Spalte möglichst im Heap zu behalten. Die Entscheidungslogik ist ein Baum: Ist die gesamte Zeile kleiner als ca. 2 kB (toast_tuple_target, Standard 2040 Bytes), wird sie direkt in den Heap geschrieben. Überschreitet sie die Schwelle, sortiert PostgreSQL die EXTENDED-Spalten nach Größe und komprimiert die größte zuerst. Reicht das, um unter die Schwelle zu kommen, wird gestoppt. Sonst geht es zur nächsten Spalte. Wenn alle komprimiert sind und die Zeile immer noch zu groß ist, wandert die größte EXTENDED- oder EXTERNAL-Spalte in die TOAST-Tabelle, ersetzt durch einen 18-Byte-Zeiger. Falls immer noch zu groß, werden auch MAIN-Spalten nachkomprimiert, und als letzte Möglichkeit wandern auch diese out-of-line.

Für variable Typen verwendet PostgreSQL das Format varlena. Es ist ein selbstbeschreibendes Format mit einem Header, der die Länge und einen Komprimierungs-Bit enthält. Nur variable Typen werden komprimiert. Fixe Typen nie. In der Praxis bedeutet das: Große TEXT-Felder werden intelligent verpackt, während eine INTEGER-Spalte unangetastet bleibt.

Kompression in Indizes – ein Sonderfall

B-Tree-Indexseiten speichern Schlüssel als IndexTuple-Einträge: ein 8-Byte-Header gefolgt vom eigentlichen Wert. Für variable Typen wird dasselbe varlena-Format verwendet. PostgreSQL prüft, ob der Heap den Wert bereits komprimiert hat. Wenn ja, kommt er komprimiert in den Index. Ist er unkomprimiert und überschreitet 510 Bytes (TOAST_INDEX_TARGET, etwa 1/16 der 8-kB-Bufferpage), dann versucht der Index, ihn selbst zu komprimieren. Passt der komprimierte Wert, wird er gespeichert. Wenn nicht, schlägt der Schreibvorgang fehl. Das erklärt, warum ein String wie repeat('x', 5000) problemlos in einem B-Tree indiziert werden kann: LZ4 komprimiert die 5000 Wiederholungen auf etwa 38 Bytes – weit unter der Grenze von 2704 Bytes. Ein zufälliger String gleicher Länge dagegen bleibt fast so groß und kann nicht indiziert werden.

Was die Zukunft bringt

Die Umstellung von pglz auf LZ4 ist mehr als ein Algorithmen-Tausch. Sie zeigt, wie PostgreSQL seine Architektur weiterentwickelt: Der frühe Fehltritt mit dedizierten komprimierten Datentypen wurde korrigiert, und die zugrunde liegende pglz-Arbeit wurde in TOAST integriert. Jetzt geht man den gleichen Weg: erst testen, dann migrieren. Das Kernteam hat sich bewusst Zeit gelassen, um sicherzustellen, dass die Änderung der richtige Weg ist. Für Entwickler und Administratoren bedeutet das: Wer PostgreSQL 19 einsetzt, profitiert automatisch von schnelleren Schreibvorgängen, ohne etwas umstellen zu müssen. Die Datenbank wird effizienter mit großen Datenmengen umgehen, besonders bei vielen INSERTs. In seltenen Fällen liefert pglz ein besseres Kompressionsverhältnis. In den meisten Alltagsszenarien überwiegen die Vorteile von LZ4. Es ist ein weiterer Schritt in Richtung einer Datenbank, die stabil, zuverlässig und performant im modernen Cloud-Zeitalter ist.

Quelle: crunchydata.com

Deine Reaktion:
Artikel teilen:
Sebastian Krötzsch
Autor

Sebastian Krötzsch

Sebastian Krötzsch schreibt auf sebask.de über Künstliche Intelligenz, Automatisierung, digitale Systeme und die Frage, was davon im Alltag wirklich nützlich ist. Ohne Buzzword-Nebel, dafür mit klarem Blick auf Praxis, Tools und echte Wirkung.