Zum Hauptinhalt springen
DevOpsMar 28, 2026

Deep EVM #25: PostgreSQL-Tabellenpartitionierung — Wenn Ihre Tabelle 10M+ Zeilen erreicht

OS
Open Soft Team

Engineering Team

Warum Partitionierung?

Sie haben eine Transaktions-Tabelle, die klein angefangen hat und jetzt bei 34 Millionen Zeilen ist. Abfragen, die frueher 50ms dauerten, brauchen jetzt 5 Sekunden. VACUUM laeuft stundenlang. Tabellenpartitionierung teilt eine logische Tabelle in mehrere physische Tabellen auf, und PostgreSQLs Abfrageplaner leitet Abfragen automatisch an die korrekten Partitionen weiter.

Partitionierungstypen

Range-Partitionierung

Ideal fuer Zeitreihen- und monoton steigende Daten:

CREATE TABLE transactions (
    id BIGINT GENERATED ALWAYS AS IDENTITY,
    block_number BIGINT NOT NULL,
    tx_hash BYTEA NOT NULL,
    from_addr BYTEA NOT NULL,
    value_wei NUMERIC NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
) PARTITION BY RANGE (block_number);

-- Partitionen erstellen
CREATE TABLE transactions_p0 PARTITION OF transactions
    FOR VALUES FROM (0) TO (1000000);
CREATE TABLE transactions_p1 PARTITION OF transactions
    FOR VALUES FROM (1000000) TO (2000000);
-- ...

List-Partitionierung

Fuer kategorische Daten:

CREATE TABLE events PARTITION BY LIST (event_type);
CREATE TABLE events_transfer PARTITION OF events FOR VALUES IN ('Transfer');
CREATE TABLE events_approval PARTITION OF events FOR VALUES IN ('Approval');

Hash-Partitionierung

Fuer gleichmaessige Verteilung ohne natuerliche Bereiche:

CREATE TABLE addresses PARTITION BY HASH (address);
CREATE TABLE addresses_p0 PARTITION OF addresses FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE addresses_p1 PARTITION OF addresses FOR VALUES WITH (MODULUS 4, REMAINDER 1);

Migration bestehender Daten

-- 1. Neue partitionierte Tabelle erstellen
CREATE TABLE transactions_new (...) PARTITION BY RANGE (block_number);

-- 2. Partitionen erstellen
-- ...

-- 3. Daten kopieren (in Batches!)
INSERT INTO transactions_new
SELECT * FROM transactions
WHERE block_number >= 0 AND block_number < 1000000;

-- 4. Tabellen tauschen
ALTER TABLE transactions RENAME TO transactions_old;
ALTER TABLE transactions_new RENAME TO transactions;

Partition Pruning

Der Abfrageplaner eliminiert nicht benoetigte Partitionen automatisch:

EXPLAIN (ANALYZE)
SELECT * FROM transactions
WHERE block_number BETWEEN 18000000 AND 18100000;

-- Ausgabe: Scannt nur die relevante Partition
-- Append (actual time=0.1..5.2 rows=50234)
--   -> Seq Scan on transactions_p18 (actual time=0.1..5.2 rows=50234)
--        Filter: block_number >= 18000000 AND block_number <= 18100000
-- 19 andere Partitionen werden NICHT gescannt

Fazit

Tabellenpartitionierung ist ein maaechtiges Werkzeug fuer grosse PostgreSQL-Tabellen. Range-Partitionierung fuer Zeitreihen, List-Partitionierung fuer Kategorien und Hash-Partitionierung fuer gleichmaessige Verteilung. Der Schluessel: Waehlen Sie den Partitionierungsschluessel so, dass er Ihren haeufigsten Abfragemuster entspricht.