Ein Tablespace in PostgreSQL ist ein benannter Verweis auf ein Verzeichnis im Dateisystem. Damit kannst du steuern, wo Tabellen, Indexe oder ganze Datenbanken physisch liegen. In der Praxis kommt das Feature seltener zum Einsatz, als man denkt — der Server-Page-Cache und moderne SSDs machen viele klassische Use-Cases obsolet. Hier eine ehrliche Bestandsaufnahme: wann lohnt sich’s, wann nicht.

Was Postgres bei der Installation mitbringt

Jeder Postgres-Cluster hat von Haus aus zwei Tablespaces:

NameZweck
pg_defaultDefault-Speicher für alle Objekte ohne explizite Tablespace-Angabe. Liegt unter <PGDATA>/base/.
pg_globalCluster-weite Objekte (Rollen, Datenbanken-Liste, …). Liegt unter <PGDATA>/global/.

Ohne weiteres Zutun landet alles in pg_default.

Eigenen Tablespace anlegen

SQL CREATE TABLESPACE
CREATE TABLESPACE fast_ssd
    OWNER app_owner
    LOCATION '/mnt/nvme/postgres';

Voraussetzungen:

  • Das Verzeichnis muss vor dem Befehl existieren.
  • Es muss dem Postgres-OS-User gehören (chown postgres:postgres).
  • Es muss leer sein.
  • Postgres muss als Superuser arbeiten — CREATE TABLESPACE ist Superuser-only.

Objekte in einem Tablespace ablegen

Beim Erstellen explizit angeben:

SQL
CREATE TABLE big_log (
    id    bigserial primary key,
    data  jsonb
) TABLESPACE fast_ssd;

CREATE INDEX big_log_data_idx ON big_log USING gin (data) TABLESPACE fast_ssd;

Bestehende Tabellen umziehen:

SQL
ALTER TABLE big_log SET TABLESPACE fast_ssd;
ALTER INDEX big_log_data_idx SET TABLESPACE fast_ssd;

ALTER TABLE … SET TABLESPACE kopiert die Daten physisch und nimmt einen ACCESS EXCLUSIVE-Lock auf die Tabelle — bei großen Tabellen kann das lange dauern und die Anwendung blockieren. Nicht in Stoßzeiten machen.

Default-Tablespace pro Datenbank festlegen:

SQL
ALTER DATABASE myapp SET TABLESPACE fast_ssd;

Wann lohnen sich Tablespaces?

Klassische Use Cases:

  1. Heiße vs. kalte Daten trennen. Aktuelle Logs auf NVMe-SSD, Archiv-Daten auf langsameren HDDs.
  2. Indexe auf separate Disks. Reduziert I/O-Konkurrenz zwischen Heap-Reads und Index-Reads.
  3. Speichergrenzen pro Datenträger umgehen. Wenn ein Volume voll ist, einen weiteren mounten und neue Tabellen darauf legen.
  4. Performance-Isolation pro Tenant. In Multi-Tenant-Setups einen Tenant auf eine eigene Disk legen.

Aber: vieles davon ist heute weniger relevant als früher. Moderne SSDs sind so schnell, dass die I/O-Konkurrenz, die in den 2000ern durch separate Disks aufgelöst wurde, heute oft kein Problem mehr ist. Wer kann, lässt erst mal alles in pg_default und tunt erst, wenn ein konkreter Engpass nachweisbar ist.

temp_tablespaces

Für temporäre Objekte (Sort-Spill, Hash-Spill bei großen Joins, temporäre Tabellen) gibt es einen Sonderparameter:

Bash postgresql.conf
temp_tablespaces = 'temp_fast'

Sinn: ein eigenes Volume für I/O-intensive temporäre Operationen. Auf einer SSD-only-Installation lohnt sich das selten; auf gemischten Setups kann es größere ORDER BYs deutlich beschleunigen, wenn der Sort nicht in den work_mem passt.

Tablespace droppen

SQL
DROP TABLESPACE fast_ssd;

Postgres lehnt ab, solange der Tablespace noch Objekte enthält. Erst alle Tabellen / Indexe in einen anderen Tablespace verschieben oder droppen, dann löst sich DROP TABLESPACE.

Inspektion

SQL
myapp=# \db+
                          List of tablespaces
    Name    |  Owner   |    Location     | Access privileges | Size
------------+----------+-----------------+-------------------+-------
 pg_default | postgres |                 |                   | 128 MB
 pg_global  | postgres |                 |                   | 612 KB
 fast_ssd   | postgres | /mnt/nvme/pg    |                   | 0 B

pg_default und pg_global haben keinen LOCATION — sie liegen innerhalb des PGDATA-Verzeichnisses.

Zu welchem Tablespace gehört eine Tabelle?

SQL
SELECT c.relname,
       COALESCE(t.spcname, 'pg_default') AS tablespace
FROM pg_class c
LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
WHERE c.relkind = 'r' AND c.relname = 'big_log';

Wenn reltablespace = 0, gehört die Tabelle zum Default-Tablespace der Datenbank.

FAQ

Geht das auch in der Cloud (RDS, Cloud SQL, …)?

In den meisten Managed-Postgres-Diensten nein. Du hast keinen Filesystem-Zugriff, keinen Superuser, und der Anbieter verwaltet Storage selbst. AWS RDS bietet seit Kurzem zwar rds_tablespace für eingeschränkte Anwendungsfälle, aber der typische Cloud-Setup ist „nicht änderbar”. Wer Tablespaces wirklich braucht, muss selbst betreiben.

Sind Tablespaces clustergebunden?

Ja. Ein Tablespace gehört zu einem Cluster, nicht zu einer Datenbank. Wenn du pg_basebackup/Streaming Replication aufsetzt, repliziert die Replika auch die Tablespace-Pfade — die Verzeichnisse müssen auf dem Replica-Host am selben Ort existieren (oder per --tablespace-mapping umgemappt werden).

Was passiert beim Backup mit Tablespaces?

pg_dump ist davon unabhängig — es macht logische Backups und ignoriert physische Speicherorte. pg_basebackup hingegen kopiert das gesamte Cluster inkl. aller Tablespace-Verzeichnisse und braucht ggf. --tablespace-mapping=…, wenn die Pfade auf dem Restore-Host anders sein sollen.

Kann ein Tablespace ueber mehrere Cluster geteilt werden?

Nein. Auch wenn das Verzeichnis theoretisch von zwei Postgres-Instanzen gleichzeitig erreichbar wäre, wäre das Datenchaos. Ein Tablespace gehört zu einem Cluster, exklusiv.

Wie schwer ist die Migration zwischen Tablespaces?

ALTER TABLE … SET TABLESPACE ist eine physische Datenkopie mit ACCESS EXCLUSIVE-Lock — die Tabelle ist während der gesamten Operation blockiert. Bei großen Tabellen ist das ein Wartungsfenster-Job. Alternativ: Logical Replication mit Cutover, falls Downtime nicht tolerierbar ist.

Wann sollte ich Tablespaces ueberhaupt anfangen einzusetzen?

Erst wenn ein konkretes Problem nachweisbar ist — z. B. dass das Volume voll wird oder I/O-Profile pro Tabelle stark abweichen. Auf SSD-only-Installationen ist das eher selten. Vorher: pg_default reicht.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Server-Administration

Zur Übersicht