Die Entwickler von OrioleDB haben den aktuellen Stand der niedrigstufigen API, die für den Zugriff von Erweiterungen auf Tabellen und Indizes in PostgreSQL (Table/Index Access Method (AM) API) verwendet wird, analysiert und Verbesserungsvorschläge unterbreitet. Seit der Einführung dieser API in PostgreSQL 12 haben die Entwickler die Möglichkeit erhalten, alternative Datenstorage-Mechanismen zu erstellen. Dennoch gibt es trotz der Existenz dieser API und der bekannten Einschränkungen des integrierten Speichermoduls bislang keine voll funktionsfähigen transaktionalen Storage-Engines, die ausschließlich als Erweiterungen implementiert sind.
Die gefragtesten Funktionen für alternative tabellarische Engines in PostgreSQL sind:
- Alternative Implementierungen von MVCC, zum Beispiel Journal-basierte UNDO-Speicher.
- Index-organisierte Tabellen, bei denen der Index kein optionales Zusatzfeature zur Tabelle ist, das Anfragen beschleunigt, sondern die Hauptdatenstruktur darstellt, in der die Tabellendaten gespeichert sind.
Die erforderlichen Änderungen an der API Table/Index AM zur Unterstützung alternativer MVCC-Implementierungen werden unter Berücksichtigung der OrioleDB-Erweiterung diskutiert, die entwickelt wurde, um die bekannten Mängel des integrierten Speichermoduls von PostgreSQL zu beheben. Das Problem besteht darin, dass für die vollständige Integration von OrioleDB in PostgreSQL Änderungen am PostgreSQL-Code erforderlich sind, was die Umsetzung des Projekts erschwert und die Notwendigkeit einer Modernisierung der aktuellen API Table AM unterstreicht.
Die API Table AM zwingt nicht direkt zu einer bestimmten Implementierung von MVCC. Dennoch machen die API Table AM und die API Index AM folgende Annahme: Jeder TID (Tuple/Row Identifier) wird entweder von allen Indizes indiziert oder gar nicht. Selbst wenn der Index AM mehrere Verweise auf einen einzigen TID hat (z. B. GIN), müssen alle diese Verweise demselben indizierten Wert entsprechen.

Dieses Prinzip wurde kritisiert wegen der Erhöhung der Schreiboperationen („write amplification“) – wenn ein indiziertes Attribut aktualisiert wird, müssen alle Indizes der Tabelle aktualisiert werden. Um die Vorteile des UNDO-Journals vollständig zu nutzen oder eine andere Speicherart ohne „Write Amplification“ (z. B. die WARM-Methode) zu entwickeln, ist es notwendig, diese Annahme zu verletzen.

Die auf UNDO basierende Table AM verletzt diese Annahme nicht und ähnelt der bestehenden HOT-Methode (Heap-Only Tuples), mit dem Unterschied, dass alte Versionen der Zeilen im UNDO-Log gespeichert werden und nicht auf derselben Seite untergebracht sein müssen. Dennoch sind die Autoren der Meinung, dass dieser Vorteil nicht ausreicht, um die Existenz einer separaten Table AM zu rechtfertigen.
Praktische Einschränkungen der bestehenden API:
- Beim Aktualisieren einer Zeile in der Tabelle werden die Indizes nach dem Prinzip „alles oder nichts“ aktualisiert.
- Mangel an der API Index AM zur punktuellen Löschung bestimmter Tuples. Derzeit können Tuples massenhaft über die Methoden ambulkdelete und amvacuumcleanup aus Indizes gelöscht werden. Ein Versuch, punktuelle Löschung über diese API zu implementieren, würde zu einer geringen Effizienz führen, da die meisten aktuellen Implementierungen den gesamten Index scannen müssen. Zudem erlaubt die API nicht anzugeben, welche der Tuples, die auf dasselbe TID verweisen, gelöscht werden sollen. Es kann nur alle löschen.
- Die Indizes verweisen derzeit auf die Zeilen der Tabelle anhand der Blocknummer (32 Bit) und der Offsetnummer (16 Bit). Nur 11 Bit der Offsetnummer können sicher vom TID der Tabelle in alle Indexzugriffsmethoden übertragen werden. Dabei müssen alternative MVCC-Implementierungen möglicherweise zusätzliche Nutzlast (payload) zusammen mit dem TID speichern. Beispielsweise benötigt OrioleDB ein oder mehrere Bits zur Implementierung der „delete-marking“-Indizes oder vollständigen Sichtbarkeitsinformationen.
Zwei Ansätze wurden vorgeschlagen, um die praktischen Einschränkungen zu überwinden:
Ansatz 1: API Index AM bietet Möglichkeiten für alternative MVCC-Implementierungen.
Während Table AM weiterhin für alle Komponenten des MVCC verantwortlich ist, bietet Index AM die erforderlichen Funktionen für alternative MVCC-Implementierungen, nämlich: Speicherung benutzerdefinierter Nutzlast (payload) zusammen mit TID, Methode zur punktuellen Löschung und sogar Methode zur punktuellen Aktualisierung (wenn TID im Index nicht geändert werden kann, kann die benutzerdefinierte Nutzlast geändert werden). Darüber hinaus müssen die Methoden der API, die beim Scannen des Index verwendet werden, aktualisiert werden, da mehrere Tuples des Index auf dasselbe TID verweisen müssen.
Ansatz 2: Indizes, die MVCC unterstützen.
Eine Alternative wäre es, Indizes zuzulassen, die MVCC unterstützen. Das heißt, der „executor“ (oder möglicherweise Table AM) ruft einfach die Methoden insert() und delete() im Index AM auf, während der Index AM die Möglichkeit bietet, basierend auf MVCC zu scannen. Dies würde das Scannen unter Verwendung nur von Indizes (index-only) erheblich vereinfachen. Selbst der gesamte Table AM könnte in diesem Fall zu einer Zwischenschicht werden, die Daten im Index speichert.
Im folgenden Diagramm ist ein Beispiel dargestellt. Der Indexwert 2 wird durch die Transaktion 11 von „A“ auf „B“ aktualisiert. Daher wird der Wert „A“ als xmax == 11 markiert, während der Wert „B“ als xmin == 11 markiert wird. Auf diese Weise kann der Index 2 gescannt werden und es werden nur die sichtbaren Tupel gemäß MVCC abgerufen, ohne Überprüfungen des Heaps (heap). Die Müllabfuhr des Index 2 kann ebenfalls ohne den Einsatz des Heaps durchgeführt werden.

Bei der Implementierung aller genannten Neuerungen im API der Indexzugriffsmethoden ist es unwahrscheinlich, dass es gelingt, alle Indizes gleichzeitig für die Unterstützung aller neuen Funktionen zu überarbeiten. Realistischer wäre es, mehrere Implementierungen für eine Indexzugriffsmethode zuzulassen. Beispielsweise könnte das Erweiterungssystem neben dem herkömmlichen B-Baum auch einen alternativen B-Baum mit Unterstützung für MVCC innerhalb des Index und Unterstützung für Aufzeichnungsidentifikatoren variabler Länge implementieren.

Daher wird vorgeschlagen, nicht nur das API des Table AM, sondern auch das API des Index AM, das der PostgreSQL-Community über viele Jahre treu gedient hat, zu überarbeiten. Darüber hinaus wird angeregt, den Index AM in eine logische Schicht und eine Implementierungsschicht zu unterteilen. Diese neu konzipierte Architektur würde es PostgreSQL ermöglichen, verschiedene Speichermodelle zu unterstützen.
Quelle: opennet.ru
