Deep EVM #25: PostgreSQL-Tabellenpartitionierung — Wenn Ihre Tabelle 10M+ Zeilen erreicht
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.