TRUNCATE vs DELETE SQL: Bedanya Apa dan Kapan Dipakai
TL;DR
TRUNCATE dan DELETE sama-sama menghapus data dari tabel, tapi cara kerjanya beda. DELETE menghapus baris satu per satu, bisa disaring pakai WHERE, dan setiap baris dicatat di log — makanya lambat tapi bisa di-rollback. TRUNCATE menghapus seluruh isi tabel sekaligus tanpa mencatat per baris, jauh lebih cepat, tapi nggak bisa pakai WHERE dan biasanya juga me-reset counter auto increment ke 1.
DELETE hapus baris satu-satu dan bisa milih pakai WHERE. TRUNCATE ngosongin seluruh tabel sekaligus, nggak bisa milih.
Itu beda utamanya. Tapi ada 4 beda lain yang bisa bikin kamu kaget kalau salah pilih — termasuk soal ID yang tiba-tiba balik ke 1, dan ROLLBACK yang ternyata nggak jalan.
Ini tabel perbandingan lengkapnya, plus aturan sederhana buat milih.
Apa bedanya TRUNCATE dan DELETE di SQL?
DELETE menghapus baris satu per satu dan mencatat tiap penghapusan di transaction log, jadi bisa disaring pakai WHERE dan bisa di-rollback. TRUNCATE mengosongkan seluruh tabel sekaligus dengan nge-dealokasi halaman datanya, jauh lebih cepat, tapi nggak punya klausa WHERE dan umumnya me-reset counter auto increment ke 1.
| Aspek | DELETE | TRUNCATE |
|---|---|---|
| Bisa pakai WHERE | Ya | Nggak |
| Kecepatan (tabel besar) | Lambat | Sangat cepat |
| Cara kerja | Hapus baris satu-satu | Lepas halaman data sekaligus |
| Transaction log | Catat tiap baris | Catat minimal |
| Reset auto increment | Nggak | Ya (biasanya) |
| Bisa di-rollback | Selalu bisa | Tergantung database |
| Kena trigger DELETE | Ya | Nggak |
| Jenis perintah | DML | DDL |
| Butuh hak akses | DELETE | Biasanya lebih tinggi |
Baris "kena trigger" itu sering kelewat. Kalau tabel kamu punya trigger yang nyatat audit log tiap ada penghapusan, TRUNCATE bakal ngelewatin trigger itu sepenuhnya — datanya hilang, log-nya kosong.
Kenapa TRUNCATE jauh lebih cepat?
DELETE harus nyatat tiap baris yang dihapus di transaction log. Itu harganya kemampuan ROLLBACK.
Hapus 10 juta baris = 10 juta catatan log.
TRUNCATE nggak ngelakuin itu. Dia langsung nge-dealokasi halaman data yang dipakai tabel — semacam ngelepas seluruh raknya sekali jalan, bukan ngambilin barang satu-satu.
Selisihnya di tabel besar itu dramatis:
| Jumlah baris | DELETE (tanpa WHERE) | TRUNCATE |
|---|---|---|
| 10.000 | ~0,3 detik | ~0,01 detik |
| 1.000.000 | ~25 detik | ~0,02 detik |
| 10.000.000 | Beberapa menit | Masih di bawah 1 detik |
Angka ini dari tes di PostgreSQL 16 di laptop biasa — anggap sebagai gambaran kasar, bukan benchmark resmi. Yang penting polanya: waktu DELETE naik seiring jumlah baris, waktu TRUNCATE hampir nggak berubah.
Itu juga alasan kenapa DELETE 10 juta baris bisa bikin disk penuh sama write-ahead log, sementara TRUNCATE nggak ngapa-ngapain.
TRUNCATE bisa di-rollback nggak?
Ini jawaban yang bikin banyak orang kena.
Tergantung databasenya.
| Database | TRUNCATE bisa ROLLBACK? |
|---|---|
| PostgreSQL | Bisa — transaksional |
| SQL Server | Bisa — transaksional |
| MySQL (InnoDB) | Nggak — auto-commit, ROLLBACK sia-sia |
| Oracle | Nggak — DDL, auto-commit |
Di PostgreSQL, ini jalan:
BEGIN;
TRUNCATE TABLE transaksi_staging;
SELECT COUNT(*) FROM transaksi_staging; -- 0
ROLLBACK;
SELECT COUNT(*) FROM transaksi_staging; -- datanya balik!
Di MySQL InnoDB, query yang sama persis bakal ngasih 0 setelah ROLLBACK. Datanya udah hilang — TRUNCATE otomatis ke-commit begitu dijalanin.
Jangan pernah asumsi. Cek dulu database yang kamu pakai. Detail perilaku transaksional TRUNCATE di PostgreSQL ada di dokumentasi resminya.
Kenapa ID balik ke 1 setelah TRUNCATE?
Karena TRUNCATE (biasanya) sekalian reset counter auto increment.
-- DELETE: ID lanjut dari terakhir
DELETE FROM transaksi;
INSERT INTO transaksi (...) VALUES (...);
SELECT id FROM transaksi; -- 8401 (lanjut dari sebelumnya)
-- TRUNCATE: ID balik dari awal
TRUNCATE TABLE transaksi;
INSERT INTO transaksi (...) VALUES (...);
SELECT id FROM transaksi; -- 1
Di PostgreSQL, perilaku defaultnya sebenernya nggak reset. Kamu harus minta eksplisit:
TRUNCATE TABLE transaksi RESTART IDENTITY;
Di MySQL, TRUNCATE selalu reset counter, nggak bisa dicegah.
Kapan ini bahaya? Kalau ada tabel lain yang nyimpen ID dari tabel ini — sistem eksternal, file ekspor lama, cache. ID 1 yang baru bisa nunjuk ke barang yang beda sama ID 1 yang lama.
Buat tabel staging, ini justru yang kamu mau.
Contoh kasus: pipeline harian toko_berkah
Aku punya pipeline yang narik data POS tiap malam ke tabel transaksi_staging, terus dibersihin dan dipindah ke tabel utama.
Tabel staging isinya rata-rata 8.400 baris per hari, dan harus dikosongin dulu tiap kali pipeline jalan.
Versi pertama pakai DELETE:
DELETE FROM transaksi_staging;
-- Waktu: 2,4 detik
Versi kedua pakai TRUNCATE:
TRUNCATE TABLE transaksi_staging RESTART IDENTITY;
-- Waktu: 0,02 detik
Seratus dua puluh kali lebih cepat. Di tabel 8.400 baris.
Tapi bukan kecepatannya yang paling ngefek. Yang paling kerasa: transaction log.
Versi DELETE bikin WAL naik sekitar 40 MB tiap malam. Tiga bulan jalan tanpa dipantau, disk-nya kepenuhan.
Versi TRUNCATE? Nyaris nol.
Aturan yang aku pakai sejak itu: tabel staging selalu pakai TRUNCATE, tabel transaksi asli selalu pakai DELETE (atau soft delete).
Soal kenapa DELETE tetap wajib buat tabel asli, aku bahas di panduan DELETE SQL — termasuk kebiasaan SELECT dulu yang bikin kamu nggak pernah kehilangan data.
Kapan pakai TRUNCATE, kapan pakai DELETE?
| Situasi | Pakai | Kenapa |
|---|---|---|
| Hapus sebagian baris | DELETE | TRUNCATE nggak punya WHERE |
| Kosongin tabel staging tiap hari | TRUNCATE | Cepat, log ringan, ID sekalian reset |
| Reset database latihan | TRUNCATE | Balik ke kondisi bersih total |
| Hapus data transaksi lama | DELETE (batch) | Butuh WHERE, butuh audit trail |
| Tabel punya trigger audit | DELETE | TRUNCATE nggak nyalain trigger |
| Tabel dirujuk foreign key | DELETE | TRUNCATE bakal ditolak |
| Di production tanpa backup | Jangan dua-duanya | Backup dulu |
Aturan singkatnya: TRUNCATE buat tabel yang emang dirancang buat dikosongin. DELETE buat data yang punya nilai historis.
Kesalahan umum
1. Ngira TRUNCATE bisa di-rollback di MySQL
Ini yang paling mahal. Kamu ketik BEGIN, ngerasa aman, TRUNCATE, terus sadar salah tabel.
ROLLBACK. Nggak ada yang balik.
Di MySQL, TRUNCATE itu DDL — sama kayak DROP TABLE. Auto-commit, nggak peduli kamu di dalam transaction atau nggak.
2. Pakai TRUNCATE di tabel yang punya foreign key
ERROR: cannot truncate a table referenced in a
foreign key constraint
Database nolak. Bagus — itu pengaman.
PostgreSQL nawarin TRUNCATE ... CASCADE, tapi hati-hati: itu ngosongin tabel anaknya juga. Kamu bisa kehilangan 8.400 transaksi cuma gara-gara mau ngosongin tabel pelanggan.
3. Ngira DELETE tanpa WHERE sama aja sama TRUNCATE
Hasil akhirnya emang sama — tabel kosong. Tapi jalurnya beda jauh.
DELETE FROM tabel; di 10 juta baris bisa makan beberapa menit, ngunci tabel, dan bikin log membengkak.
TRUNCATE TABLE tabel; selesai sebelum kamu sempet ngangkat jari dari tombol.
4. Lupa TRUNCATE nggak nyalain trigger
Kalau kamu punya trigger yang nulis ke audit_log tiap ada baris kehapus, TRUNCATE bakal ngelewatinnya diam-diam.
Data hilang, jejaknya nggak ada. Di tabel yang kena audit compliance, ini masalah serius.
Konsep transaction dan foreign key yang jadi dasar semua ini ada di glosarium.
FAQ
Apa bedanya TRUNCATE dan DELETE di SQL?
DELETE menghapus baris satu per satu dan bisa disaring pakai WHERE, tapi lambat karena tiap baris dicatat di log. TRUNCATE ngosongin seluruh tabel sekaligus tanpa nyatat per baris, jadi jauh lebih cepat, tapi nggak bisa milih baris. TRUNCATE juga biasanya me-reset counter auto increment ke 1.
TRUNCATE bisa di-rollback nggak?
Tergantung databasenya. Di PostgreSQL dan SQL Server, TRUNCATE transaksional — bisa dibungkus BEGIN dan ROLLBACK. Di MySQL InnoDB dan Oracle, TRUNCATE itu DDL dan langsung ter-commit otomatis, jadi ROLLBACK nggak berguna. Jangan pernah asumsi, cek dulu database yang kamu pakai.
Kenapa TRUNCATE jauh lebih cepat dari DELETE?
Karena TRUNCATE nggak mencatat penghapusan per baris. Dia langsung nge-dealokasi halaman data yang dipakai tabel itu. DELETE harus nyatat tiap baris di transaction log biar bisa di-rollback. Di tabel 10 juta baris, selisihnya bisa dari beberapa menit jadi di bawah satu detik.
Bisa nggak TRUNCATE pakai WHERE?
Nggak bisa. TRUNCATE nggak punya klausa WHERE sama sekali — dia operasi all-or-nothing. Kalau kamu cuma mau hapus sebagian baris, DELETE satu-satunya pilihan. Ini bedanya paling mendasar antara keduanya.
TRUNCATE atau DELETE buat tabel staging?
TRUNCATE. Tabel staging biasanya diisi ulang penuh tiap kali pipeline jalan, jadi kamu emang mau ngosongin semuanya. TRUNCATE jauh lebih cepat dan sekalian reset ID-nya. DELETE tanpa WHERE hasilnya sama, tapi bisa berkali-kali lipat lebih lambat dan bikin transaction log membengkak.
Penutup
Cara paling gampang inget bedanya:
- Butuh WHERE? DELETE. Itu satu-satunya yang bisa milih baris.
- Ngosongin tabel staging? TRUNCATE. Cepat, log ringan, ID sekalian reset.
- Pakai MySQL? Anggap TRUNCATE nggak bisa di-rollback. Karena emang nggak bisa.
Copy DDL dan query di artikel ini ke database latihan kamu, terus coba sendiri BEGIN-TRUNCATE-ROLLBACK. Ngerasain langsung perbedaannya di database kamu sendiri jauh lebih nempel daripada percaya sama tabel di artikel.
Belum baca soal cara pakai DELETE yang aman? Mulai dari panduan DELETE SQL.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel Terkait
Churn Rate SQL: Deteksi Pelanggan yang Kabur Sejak Dini
Studi kasus toko_berkah: 1.240 pelanggan hilang dalam setahun, dan sinyalnya udah kelihatan 2 bulan sebelumnya. Ini query yang bikin kamu nangkap mereka lebih awal.
YoY Growth SQL: Bandingkan Performa dengan Tahun Lalu
Hitung YoY growth di SQL pakai LAG atau self-join, lengkap dengan cara ngindarin pembagi nol dan jebakan bulan yang bolong. Contohnya pakai data toko_berkah.
MoM Growth SQL: Hitung Pertumbuhan Bulanan Otomatis
Berhenti copy-paste omzet bulan lalu ke Excel buat ngitung growth. Satu query SQL pakai LAG bisa ngasih pertumbuhan bulanan otomatis, lengkap sampai bulan yang datanya kosong.