Langsung ke konten utama
DevOpsMar 28, 2026

Partisi Tabel PostgreSQL — Ketika Tabel Anda Mencapai 10 Juta+ Baris

OS
Open Soft Team

Engineering Team

Kapan Mempartisi

Partisi tabel adalah teknik membagi satu tabel logis menjadi beberapa tabel fisik yang lebih kecil. PostgreSQL mengelolanya secara transparan — query terhadap tabel utama secara otomatis diarahkan ke partisi yang relevan.

Anda perlu mempertimbangkan partisi ketika:

  • Tabel memiliki lebih dari 10 juta baris
  • Query WHERE selalu menyertakan kolom tertentu (tanggal, locale, tenant)
  • VACUUM memakan waktu terlalu lama
  • Anda perlu menghapus data lama secara efisien

Jenis Partisi

1. Range Partitioning

Paling umum. Membagi berdasarkan rentang nilai — biasanya tanggal:

CREATE TABLE events (
    id UUID DEFAULT gen_random_uuid(),
    event_type TEXT NOT NULL,
    payload JSONB NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
) PARTITION BY RANGE (created_at);

-- Partisi per bulan
CREATE TABLE events_2024_01 PARTITION OF events
    FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
CREATE TABLE events_2024_02 PARTITION OF events
    FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
CREATE TABLE events_2024_03 PARTITION OF events
    FOR VALUES FROM ('2024-03-01') TO ('2024-04-01');

2. List Partitioning

Membagi berdasarkan nilai diskrit — cocok untuk multi-tenant atau multi-locale:

CREATE TABLE articles (
    id UUID DEFAULT gen_random_uuid(),
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    locale TEXT NOT NULL,
    published_at TIMESTAMPTZ
) PARTITION BY LIST (locale);

CREATE TABLE articles_en PARTITION OF articles FOR VALUES IN ('en');
CREATE TABLE articles_id PARTITION OF articles FOR VALUES IN ('id');
CREATE TABLE articles_ru PARTITION OF articles FOR VALUES IN ('ru');
CREATE TABLE articles_other PARTITION OF articles DEFAULT;

3. Hash Partitioning

Mendistribusikan baris secara merata — cocok ketika tidak ada kolom range/list yang jelas:

CREATE TABLE user_sessions (
    id UUID DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL,
    data JSONB,
    created_at TIMESTAMPTZ DEFAULT NOW()
) PARTITION BY HASH (user_id);

CREATE TABLE user_sessions_0 PARTITION OF user_sessions
    FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE user_sessions_1 PARTITION OF user_sessions
    FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE user_sessions_2 PARTITION OF user_sessions
    FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE user_sessions_3 PARTITION OF user_sessions
    FOR VALUES WITH (MODULUS 4, REMAINDER 3);

Migrasi dari Tabel Non-Partisi

-- 1. Rename tabel asli
ALTER TABLE events RENAME TO events_old;

-- 2. Buat tabel partisi baru
CREATE TABLE events (...) PARTITION BY RANGE (created_at);

-- 3. Buat partisi
CREATE TABLE events_2024_01 PARTITION OF events ...;

-- 4. Migrasikan data
INSERT INTO events SELECT * FROM events_old;

-- 5. Verifikasi dan hapus tabel lama
DROP TABLE events_old;

Partition Pruning

Partition pruning adalah optimasi di mana PostgreSQL hanya memindai partisi yang relevan:

-- Hanya memindai events_2024_01
EXPLAIN SELECT * FROM events WHERE created_at = '2024-01-15';

-- Output:
-- Append
--   -> Seq Scan on events_2024_01
--        Filter: (created_at = '2024-01-15')

Tanpa partisi, query akan memindai seluruh tabel. Dengan partisi, PostgreSQL melewatkan partisi yang tidak relevan.

Dampak pada Performa

OperasiTanpa PartisiDengan Partisi
SELECT WHERE dateFull scan 100M rowsScan 1 partisi (~3M rows)
DELETE data lamaSlow, generates WALDROP TABLE, instant
VACUUMLocks 100M row tableVacuum per partisi
Index rebuildHoursMinutes per partisi

Otomatisasi Partisi

-- Buat partisi secara otomatis dengan pg_partman
CREATE EXTENSION pg_partman;

SELECT partman.create_parent(
    p_parent_table => 'public.events',
    p_control => 'created_at',
    p_type => 'native',
    p_interval => '1 month',
    p_premake => 3  -- Buat 3 partisi ke depan
);

Kesimpulan

Partisi tabel PostgreSQL adalah teknik kritis ketika data tumbuh melewati 10 juta baris. Range partitioning untuk data time-series, list untuk multi-tenant/locale, dan hash untuk distribusi merata. Partition pruning memastikan query hanya menyentuh data yang relevan, dan maintenance (VACUUM, reindex) menjadi jauh lebih cepat.