Datenbanken sind aus modernen Anwendungen nicht mehr wegzudenken. Ob Online-Shops, soziale Netzwerke oder Unternehmensanwendungen – sie alle basieren auf dem effizienten Speichern und Abrufen von Daten. Auf den ersten Blick scheint das Anlegen und Befüllen einer Tabelle in einer Datenbank eine simple Angelegenheit zu sein. Man definiert Spalten und fügt Daten ein. Doch wie genau speichert das System diese Tabellen eigentlich physisch auf der Festplatte? Wie werden die Daten organisiert, damit sie schnell gefunden und effizient verarbeitet werden können? Diese Fragen bleiben oft unbeantwortet, obwohl ein tieferes Verständnis für die interne Speicherung sogar bei der Optimierung von Datenbankanwendungen helfen kann.
Im Kern versteht ein Computer nämlich keine Tabellen, sondern nur Bits und Bytes. Die Herausforderung besteht darin, eine logisch strukturierte Tabelle aus Zeilen und Spalten in eine physische Darstellung zu übersetzen, die effektiv auf der Festplatte abgelegt werden kann. Dabei spielen verschiedene Datenstrukturen und Ablageformen eine wesentliche Rolle. Ein grundlegendes Konzept dafür sind die sogenannten Seiten, oder englisch Pages, die das Kleinste sind, was von der Festplatte gelesen oder geschrieben wird. Eine Seite ist ein Block fester Größe, beispielsweise acht Kilobyte bei PostgreSQL oder sechzehn Kilobyte bei MySQL, in dem Daten gebündelt gespeichert werden.
Die Daten werden also nie einzeln als einzelne Zeile eingelesen, sondern immer als ganze Seiten, die mehrere Zeilen enthalten können. Diese Vorgehensweise optimiert den Zugriff, da bei einer einzigen Ein-/Ausgabeoperation gleich mehrere zusammenhängende Datensätze in den Speicher geladen werden und somit die Zugriffsgeschwindigkeit verbessert wird. Das Konzept der Seiten spielt auch bei der Speicherverwaltung im Arbeitsspeicher, genauer im sogenannten Buffer Pool, eine wichtige Rolle. Geladene Seiten aus der Festplatte werden dort zwischengespeichert, wodurch wiederholtes Lesen derselben Daten deutlich schneller erfolgen kann. Ein weiterer Kernbegriff für die physische Datenablage ist der sogenannte Heap.
Im Datenbankkontext ist ein Heap keine Prioritätswarteschlange, sondern eine Struktur, in der die tatsächlichen Datenseiten ohne bestimmte Ordnung hintereinander abgelegt werden. Das bedeutet, dass die Reihenfolge der Daten im Heap zufällig ist, abhängig davon, wo gerade Plattenplatz frei ist. Diese Art der Ablage erleichtert zwar das schnelle Schreiben neuer Datensätze, erschwert jedoch das gezielte Finden bestimmter Daten, da komplexe Suchoperationen auf einen vollständigen Tabellenscan hinauslaufen. Um diese Suchoperationen zu optimieren, kommen Indexe ins Spiel. Ein Index ist ein begleitendes Datenstruktur-Set, das auf ausgewählten Spalten basiert und schnellen Zugriff auf die Daten garantiert.
Dabei werden Verknüpfungen zu den tatsächlichen Daten im Heap gespeichert, sodass die Datenbank zuerst den Index einliest, um die gesuchten Positionen herauszufinden, bevor sie die passenden Seiten aus dem Heap lädt. In der Praxis werden Indexe meist als B-Bäume organisiert, die eine ausgewogene Baumstruktur mit schnellen Suchzugriffen bieten. Durch diese Organisation können Anfragen wie das Finden eines bestimmten Datensatzes mit logarithmischer Zeitkomplexität durchgeführt werden – also sehr viel schneller als der lineare Scan eines Heaps. Besonders erwähnenswert ist hier der Unterschied zwischen sekundären Indexen und sogenannten Clustered Indexen. Während sekundäre Indexe lediglich Zeiger auf die Position von Datensätzen im Heap enthalten und unabhängig von deren physischer Anordnung sind, bewirkt ein Clustered Index eine physische Sortierung der Daten nach den Schlüsseln des Indexes.
Dementsprechend gibt es pro Tabelle immer nur einen Clustered Index, da die Daten nur auf eine Weise geordnet sein können. Ein praktisches Beispiel hierfür ist MySQLs InnoDB-Storage-Engine, die standardmäßig die Primärschlüssel einer Tabelle verwendet, um die Daten im Clustered Index physisch zu sortieren. Dies führt dazu, dass Datensätze nach ihrem Primärschlüssel auf der Platte sortiert abgelegt werden, was vor allem bei Bereichsabfragen und gezieltem Zugriff auf Datensätze mit bekannten Schlüsseln die Leistungsfähigkeit deutlich steigert. Interessanterweise ist bei Tabellen ohne definierten Primärschlüssel InnoDB verpflichtet, eine interne versteckte Spalte als eindeutige Zeilen-ID zu erzeugen, um die physische Organisation zu gewährleisten und eine Leistungsoptimierung zu ermöglichen. Das Ergebnis ist ein stets existierender Clustered Index, der die physische Datenstruktur organisiert, auch wenn kein expliziter Primärschlüssel definiert wurde.
Die Wahl der Schlüssel spielt dabei ebenfalls eine Rolle: Verwendung manuell oder automatisch inkrementierender Integer-Werte als Primärschlüssel sorgt für sequenzielle Einfügungen am Ende der Tabelle, was Fragmentierungen und häufige Umsortierungen im Clustered Index verhindert. Werden hingegen zufällige Werte wie UUIDs als Primärschlüssel verwendet, entstehen unvorhersehbare Einfügungen im Index, was zu häufigen Seitenaufteilungen, Fragmentierungen und höheren Ein-/Ausgabeoperationen führt – dies wirkt sich negativ auf die Performance aus. Deshalb ist es oft ratsam, zufällige Primärschlüssel als sekundäre Indexe zu verwenden und den Primärschlüssel selbst mit einer sequentiellen ID zu gestalten. Ein weiterer wichtiger Mechanismus ist das sogenannte Write-Ahead-Logging, kurz WAL. Wenn Daten in der Datenbank geändert werden, erfolgt die Änderung nicht sofort in der Datendatei.
Stattdessen wird zuerst eine Protokolldatei beschrieben, das Journal, in dem die Änderungen dokumentiert werden. Diese Methode gewährleistet, dass bei einem unerwarteten Systemausfall die Integrität der Daten garantiert werden kann, da das System mithilfe des WALs alle Änderungen nachvollziehen und im Zweifel wiederherstellen kann. Die tatsächlichen Änderungen an den Datendateien werden in einem nachgelagerten Schritt durchgeführt. Ein Verständnis dieser Abläufe ist daher essenziell, um Datenverlust zu vermeiden und robuste Anwendungen zu entwickeln. Zudem zeigt sich beim Umgang mit Datenbanken, dass die unterschiedlichen Systeme verschieden vorgehen, um interne Zeilenidentifikatoren zu verwalten.
So verfügt etwa PostgreSQL über eine interne, für den Benutzer unsichtbare Spalte namens „ctid“, die jede Zeile eindeutig identifiziert. Diese „tuple ID“ setzt sich aus einem Blocknummer und einem Index innerhalb dieses Blocks zusammen und verweist präzise auf die physische Speicherposition der Zeile im Heap. Im Gegensatz dazu verwendet MySQL mit InnoDB bei nicht vorhandenen Primärschlüsseln die erwähnte versteckte 6-Byte interne Zeilen-ID. Ein sehr interessantes Verhalten zeigt PostgreSQL, wenn Daten aktualisiert werden. Aufgrund des Multi-Version Concurrency Control-Prinzips (MVCC) werden Zeilen bei Änderungen nicht direkt überschrieben.
Stattdessen erzeugt das System eine neue Version der Zeile und lässt die alte bestehen, bis diese durch eine Wartungsoperation wie VACUUM entfernt wird. Dies bewirkt, dass auch die Indexe aktualisiert werden müssen, da sie auf die physischen Zeilenreferenzen zeigen. Dieser Mechanismus erlaubt eine höhere Parallelität bei Lese- und Schreiboperationen und stellt sicher, dass mehrere Transaktionen konsistent und ohne Blockaden ablaufen können. Abschließend lässt sich festhalten, dass das Verständnis der physischen Speicherung von Datenbanken – angefangen bei der Ablage in Pages und Heaps, über die Nutzung von Indexen und Clustered Indexen, bis hin zu Log-Mechanismen wie WAL und MVCC – wesentlich ist, um Datenbankperformance zu maximieren. Wer diese Grundlagen erkennt, kann die Architektur von Datenbanken besser nachvollziehen und insbesondere in anspruchsvollen Anwendungen von Optimierungen profitieren.
Dabei zeigen verschiedene Datenbanksysteme unterschiedliche Strategien, aber die zugrundeliegenden Prinzipien bleiben oftmals ähnlich. In jedem Fall gilt: Der physische Speicheraufbau entscheidet maßgeblich darüber, wie schnell und effizient Daten abgefragt und verarbeitet werden können. Dieses Wissen hilft Entwicklerinnen und Entwicklern, strukturierte Projekte von Anfang an performant und zuverlässig zu gestalten.