Partisi Tabel di SQL untuk Data Besar
TL;DR
Partisi tabel di SQL memecah satu tabel besar jadi beberapa subtabel fisik berdasarkan kolom kunci kayak tanggal, tapi tetap kelihatan sebagai satu tabel saat di-query. Manfaatnya, database cuma memindai partisi yang cocok dengan filter, jadi query di tabel jutaan baris bisa turun dari detik ke milidetik. Di PostgreSQL kamu bikinnya pakai PARTITION BY RANGE, LIST, atau HASH.
Partisi tabel di SQL itu cara memecah satu tabel besar jadi beberapa potongan fisik yang lebih kecil, tapi tetap kelihatan sebagai satu tabel waktu kamu query. Tujuannya biar database cuma baca potongan yang relevan, bukan seluruh tabel.
Buat tabel transaksi yang udah tembus puluhan juta baris, ini beda antara query yang jalan 6 detik dan query yang jalan setengah detik.
Di sini kamu bakal belajar cara kerja partisi tabel, cara bikinnya di PostgreSQL, bedanya tipe RANGE, LIST, dan HASH, plus contoh nyata pakai data toko_berkah. Aku juga bahas kesalahan yang bikin partisi malah gak kepakai.
Apa itu partisi tabel di SQL?
Partisi tabel adalah teknik membagi satu tabel logis jadi beberapa subtabel fisik berdasarkan nilai kolom tertentu, misalnya tanggal atau wilayah. Kamu tetap query ke satu nama tabel. Tapi database cuma menyentuh partisi yang cocok sama filter. Hasilnya scan jadi lebih kecil dan query lebih ngebut.
Bedanya sama index database, partisi motong data di level penyimpanan. Index bikin pencarian dalam satu tabel lebih cepat. Partisi bikin sebagian besar tabel gak perlu disentuh sama sekali. Dua-duanya bisa dipakai bareng.
Nama teknisnya di PostgreSQL: declarative partitioning. Kamu deklarasi satu tabel induk, lalu bikin partisi anak di bawahnya.
Kapan kamu butuh partisi tabel?
Kamu butuh partisi kalau tabelnya udah besar (biasanya di atas beberapa juta baris) dan query kamu hampir selalu filter di kolom yang sama, kayak tanggal. Kalau tabelnya masih ratusan ribu baris, index biasa udah cukup dan partisi cuma nambah ribet.
Tanda-tanda tabel kamu kandidat partisi:
- Tabel log atau transaksi yang tumbuh terus tiap hari.
- Query dashboard selalu filter per bulan atau per kuartal.
- Kamu rutin hapus data lama, misalnya buang transaksi di atas 2 tahun.
Poin terakhir itu keuntungan yang sering kelupaan. Hapus satu partisi lama pakai DROP TABLE jauh lebih cepat dari DELETE jutaan baris.
Gimana cara bikin partisi tabel di PostgreSQL?
Kamu bikin tabel induk dengan klausa PARTITION BY, lalu bikin partisi anak yang nentuin rentang nilainya. Tabel induk sendiri gak nyimpen data, cuma jadi pintu masuk. Setiap baris otomatis masuk ke partisi yang cocok waktu di-INSERT.
-- Tabel induk dipartisi per rentang tanggal
CREATE TABLE transaksi (
id bigint,
tanggal date NOT NULL,
id_pelanggan int,
total numeric
) PARTITION BY RANGE (tanggal);
-- Partisi per bulan
CREATE TABLE transaksi_2026_09
PARTITION OF transaksi
FOR VALUES FROM ('2026-09-01') TO ('2026-10-01');
CREATE TABLE transaksi_2026_10
PARTITION OF transaksi
FOR VALUES FROM ('2026-10-01') TO ('2026-11-01');
Perhatiin batas atasnya eksklusif. FOR VALUES FROM ('2026-09-01') TO ('2026-10-01') nampung 1 sampai 30 September, bukan sampai 1 Oktober. Jadi gak ada tanggal yang dobel masuk dua partisi.
Kolom yang dipakai buat partisi wajib jadi bagian dari primary key kalau kamu bikin primary key. Ini aturan PostgreSQL yang sering bikin pemula bingung.
Apa bedanya partisi RANGE, LIST, dan HASH?
Ada tiga strategi partisi utama. RANGE buat rentang berurutan kayak tanggal atau angka. LIST buat nilai kategori yang jelas kayak nama kota. HASH buat nyebar baris rata waktu gak ada kolom yang logis buat dibagi.
| Tipe | Dipakai buat | Contoh kolom |
|---|---|---|
| RANGE | Nilai berurutan atau rentang | tanggal, tahun, umur |
| LIST | Kategori diskrit yang jumlahnya sedikit | kota, status, wilayah |
| HASH | Sebar merata tanpa kolom logis | id_pelanggan |
Contoh partisi LIST per wilayah:
CREATE TABLE penjualan (
id bigint,
wilayah text,
total numeric
) PARTITION BY LIST (wilayah);
CREATE TABLE penjualan_jawa
PARTITION OF penjualan
FOR VALUES IN ('Jakarta', 'Bandung', 'Surabaya');
CREATE TABLE penjualan_luar_jawa
PARTITION OF penjualan
FOR VALUES IN ('Medan', 'Makassar', 'Denpasar');
Buat kebanyakan kasus analis di Indonesia, RANGE per tanggal yang paling sering kepakai. Data transaksi dan log hampir selalu diakses per periode waktu.
Partition pruning: kenapa query jadi cepat?
Partition pruning adalah proses database membuang partisi yang gak relevan sebelum baca data. Kalau kamu filter WHERE tanggal >= '2026-10-01', PostgreSQL langsung tau partisi September dan sebelumnya gak perlu disentuh. Cuma partisi Oktober yang dibaca.
Kamu bisa cek pruning jalan atau gak pakai EXPLAIN:
EXPLAIN
SELECT COUNT(*), SUM(total)
FROM transaksi
WHERE tanggal >= '2026-10-01' AND tanggal < '2026-11-01';
Di hasilnya, kamu mau lihat cuma satu partisi yang muncul di rencana eksekusi. Kalau semua partisi kelihatan, berarti pruning gagal dan filter kamu perlu diperbaiki. Ini biasanya gara-gara kolom partisi dibungkus fungsi.
Contoh kasus: partisi transaksi toko_berkah
Toko_berkah punya tabel transaksi yang udah nyimpen 4 tahun data. Dari dataset ngulikdata, tabel ini isinya 18,4 juta baris. Query rekap penjualan Oktober tadinya jalan 6,2 detik karena database scan seluruh tabel tiap kali.
Setelah dipartisi per bulan pakai RANGE, query yang sama turun jadi 0,4 detik. Bedanya 15 kali lebih cepat, cuma dari mecah tabel per bulan tanpa nambah hardware.
-- Rekap penjualan per kota, bulan Oktober
SELECT
id_pelanggan,
COUNT(*) AS jumlah_order,
SUM(total) AS total_belanja
FROM transaksi
WHERE tanggal >= '2026-10-01'
AND tanggal < '2026-11-01'
GROUP BY id_pelanggan
ORDER BY total_belanja DESC
LIMIT 20;
Query ini cuma baca partisi transaksi_2026_10 yang isinya sekitar 400 ribu baris, bukan 18,4 juta. Itu alasan lonjakan kecepatannya. Buat pola lain kayak ambil peringkat pelanggan, kamu bisa gabung ini sama Top N per grup.
Kesalahan umum saat pakai partisi tabel
Kesalahan paling sering: bungkus kolom partisi pakai fungsi di klausa WHERE. Begitu kamu tulis WHERE EXTRACT(MONTH FROM tanggal) = 10, pruning mati dan semua partisi kebaca. Filter langsung ke kolom mentahnya pakai rentang tanggal.
Kesalahan kedua: lupa bikin partisi buat data baru. Kalau baris masuk dengan tanggal yang gak punya partisi, INSERT-nya error. Bikin partisi ke depan atau pakai DEFAULT partition buat nampung sisa.
Kesalahan ketiga: mecah tabel jadi terlalu banyak partisi kecil. Ribuan partisi malah bikin perencanaan query lambat. Buat kebanyakan kasus, partisi per bulan atau per tahun udah pas. Kalau kamu masih ragu soal kapan index lebih cocok, cek dulu composite index di SQL.
Buat mengatur tanggal partisi ke depan, tabel kalender bantu banget. Aku bahas caranya di membuat tabel kalender di SQL, dan konsep partisi tabel ada di glosarium.
FAQ
Apa bedanya partisi tabel dan index?
Index bikin pencarian dalam satu tabel lebih cepat dengan nyimpen pointer terurut. Partisi motong tabel jadi potongan fisik, jadi sebagian besar data gak perlu disentuh sama sekali. Buat tabel jutaan baris yang selalu difilter per periode, gabungan keduanya paling kenceng: partisi per bulan, plus index di dalam tiap partisi.
Berapa besar tabel baru layak dipartisi?
Gak ada angka mutlak, tapi patokan umum di atas beberapa juta baris atau ukuran tabel udah lewat memori server. Di bawah itu, index biasa udah cukup dan partisi cuma nambah kerumitan. Ukur dulu pakai EXPLAIN sebelum mutusin. Kalau query masih cepat, kamu belum butuh partisi.
Apakah partisi tabel bikin INSERT jadi lambat?
Sedikit, karena database harus nentuin partisi tujuan tiap baris. Tapi bedanya kecil banget dan hampir selalu kebayar sama kecepatan query. Yang perlu kamu jaga cuma pastiin partisi tujuan udah ada. Baris dengan nilai di luar semua partisi bakal ditolak kalau gak ada partisi DEFAULT.
Apakah partisi tabel ada di MySQL juga?
Ada. MySQL punya PARTITION BY RANGE, LIST, HASH, dan KEY dengan sintaks yang mirip. Konsep partition pruning-nya sama. Yang beda cuma detail sintaks dan beberapa batasan, misalnya soal foreign key. Prinsip yang kamu pelajari di sini kepakai di dua-duanya.
Gimana cara hapus data lama di tabel terpartisi?
Cukup DROP partisi yang mau dibuang, misalnya DROP TABLE transaksi_2022_01. Operasinya instan karena database tinggal lepas satu file, bukan hapus baris satu-satu. Ini jauh lebih cepat dan ringan dari DELETE jutaan baris yang bikin tabel mengembang dan butuh VACUUM.
Penutup
Tiga hal yang perlu kamu inget soal partisi tabel:
- Partisi memecah tabel besar jadi potongan, jadi query cuma baca yang relevan.
- RANGE per tanggal paling sering kepakai buat data transaksi.
- Jaga filter langsung ke kolom partisi biar pruning jalan.
Mau latihan langsung nulis query di tabel besar tanpa install database? Coba NgulikSQL buat praktek query dari nol sampai mahir. Habis itu lanjut baca covering index di SQL biar query kamu makin ngebut.
Referensi resmi soal sintaks lengkapnya ada di dokumentasi PostgreSQL tentang table partitioning.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Fungsi NTH_VALUE di SQL untuk Ambil Nilai ke-N (2026)
NTH_VALUE ngambil nilai baris ke-N dalam window, tapi frame default-nya sering bikin hasil NULL. Ini sintaksnya, cara benerin frame, plus contoh transaksi toko.
Running Max dan Min dengan Window Function SQL
Lacak nilai tertinggi dan terendah berjalan di SQL pakai window function MAX dan MIN OVER. Ini sintaks, frame clause, dan contoh rekor omzet toko.
Analisa Afinitas Produk (Cross-Sell) dengan SQL
Produk apa yang sering dibeli bareng? Analisa afinitas produk pakai SQL self JOIN jawab itu. Ini cara hitung support, confidence, dan lift buat strategi cross-sell.