Pernah ngerasa aneh nggak? Lu baru aja ngehapus jutaan baris data log lama dari production database Postgres lu buat ngurangin beban server, tapi ujung-ujungnya CPU load malah meledak dan storage nggak nambah lega sedikit pun.
Kalau lu lagi nyari tahu kenapa query DELETE malah bikin database Postgres makin lambat, jawabannya ada di arsitektur MVCC (Multi-Version Concurrency Control). Di Postgres, perintah DELETE nggak langsung membuang data dari disk, melainkan cuma ngasih tanda (dead tuple) yang bikin I/O server kerja keras. Cara paling scalable dan aman buat menghapus data dalam jumlah masif di database adalah dengan mendesain Table Partitioning sejak awal, lalu menggunakan perintah DROP TABLE atau TRUNCATE untuk membuang partisi lama dalam sekejap tanpa overhead I/O.
Kenapa Query DELETE Itu Berbahaya Buat Skala Masif?
Gua sering banget lihat pola ini waktu backend developer lagi panic mode ngeliat storage database yang makin menipis. Naluri pertama biasanya langsung nulis script untuk jalanin query kayak gini:
DELETE FROM user_logs WHERE created_at < NOW() - INTERVAL '1 year';
Kelihatannya simpel dan beres. Tapi kalau data user_logs lu isinya puluhan atau ratusan juta baris, query ini adalah resep bencana buat performa aplikasi lu. Kenapa?
- DELETE itu sebenarnya UPDATE: Berkat arsitektur MVCC di Postgres, data nggak langsung hilang. Postgres cuma nge-mark baris tersebut sebagai dead tuple biar transaksi lain masih bisa ngebaca data tersebut kalau diperlukan.
- I/O Amplification: Postgres harus nulis perubahan ini ke disk dan juga ngupdate index yang nyambung ke baris-baris tersebut. Ini ngabisin resource I/O dan nambahin WAL (Write-Ahead Log) yang bikin disk lu ngos-ngosan.
- Table Bloat: Karena data aslinya masih ada di disk (tapi cuma dikasih label "mati"), ukuran tabel lu nggak otomatis mengecil. Lu baru bisa dapet space-nya lagi kalau proses
VACUUMudah jalan. Sialnya,VACUUMpada tabel raksasa juga ngabisin resource CPU dan memori.
The Only Scalable Delete is DROP TABLE
Ini konsep yang lumayan ngetren dan dibahas tajam sama engineering blog-nya PlanetScale: satu-satunya cara hapus data skala masif yang benar-benar scalable adalah DROP TABLE (atau TRUNCATE).
Beda sama DELETE yang harus nyentuh data baris demi baris, DROP TABLE dan TRUNCATE adalah operasi DDL (Data Definition Language). Operasi ini nggak ngecek baris per baris. Postgres cuma perlu ngehapus file pointer dari disk secara langsung. Proses ini selesai dalam hitungan milidetik, tanpa dead tuples, tanpa nyiksa I/O, dan storage lu langsung lega detik itu juga.
Cara Implementasi Buat Backend Developer
Nah, pertanyaannya: masa iya gua hapus tabel utama gua? Jelas nggak. Solusinya adalah nerapin Table Partitioning.
Alih-alih nyimpen semua data log atau transaksi historis di satu tabel raksasa, lu bagi tabel itu berdasarkan periode waktu (misalnya per bulan atau per minggu). Postgres udah punya fitur native buat ini.
Contoh Praktis:
- Bikin tabel utama (Parent Table):
Buat tabeluser_logssebagai partitioned table berdasarkan kolom tanggal. - Bikin tabel partisi (Child Tables):
Otomatis (atau manual) bikin tabel turunan kayakuser_logs_2026_01,user_logs_2026_02, dan seterusnya. - Hapus partisi lama:
Pas data log Januari 2026 udah nggak kepakai dan umurnya udah lewat aturan retensi lu, jangan jalaninDELETE. Lu cukup jalaninDROP TABLE user_logs_2026_01;.
Begitu DROP TABLE dieksekusi, data lenyap seketika, disk space langsung balik, dan performa query lain nggak bakal terganggu sama sekali.
Takeaways dan Mindset Shift
Buat lu yang lagi ngebangun sistem backend dan udah mulai mikirin soal data retention, ini beberapa poin penting yang bisa lu jadiin patokan:
- Kalau data lu sifatnya kayak log, time-series, atau analytics yang gedenya eksponensial, pakai table partitioning sejak hari pertama. Jangan nunggu tabelnya tembus jutaan baris.
- Kalau terpaksa harus pakai
DELETEkarena arsitektur udah kepalang tanggung, hapus datanya dalam batch kecil (misal 5.000 baris per transaksi) dengan jeda waktu (sleep). Jangan pernah ngehajar puluhan juta baris dalam satu transaksi. - Selalu monitor proses autovacuum di database lu. Tabel yang kena operasi
DELETEatauUPDATEberat bakal sering ngalamin bloat kalau autovacuum-nya nggak dikonfigurasi dengan agresif.
Ngoding backend itu bukan cuma soal gimana data bisa masuk secepat mungkin, tapi juga gimana data lama bisa keluar tanpa bikin sistem batuk-batuk.