Menu

Backup dan Restore SQLite: .backup, VACUUM INTO, dan Online API

Cara melakukan backup dan restore database SQLite dengan aman: perintah .backup, VACUUM INTO, online backup API, dan kenapa menyalin file adalah langkah yang keliru.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Kenapa Kamu Tidak Bisa Sekadar cp File-nya

Database SQLite adalah satu file, jadi menggoda untuk mem-backup-nya dengan menyalin file biasa. Kadang cara itu berhasil. Sering kali tidak.

Ada dua hal yang bisa salah:

  • Koneksi lain sedang menulis saat kamu menyalin. File tujuan berakhir dengan transaksi yang baru setengah diterapkan, sehingga rusak saat dibuka.
  • Database berada dalam mode WAL (bawaan di sebagian besar aplikasi modern). Perubahan terbaru disimpan di file terpisah database.db-wal. Kalau hanya file utama yang disalin, kamu kehilangan data tanpa sadar.

SQLite menyediakan alat yang tepat untuk ini. Alat-alat itu menangani lock, isi WAL, dan penulis yang berjalan bersamaan tanpa kejutan. Pakai itu, bukan cp.

Perintah .backup

Cara tercepat untuk mem-backup database dari CLI adalah dot command .backup:

sqlite3 app.db
sqlite> .backup backup.db
sqlite> .quit

Perintah itu menulis salinan lengkap app.db ke backup.db. Ia tetap bekerja meskipun proses lain sedang membaca atau menulis database: backup API mengambil serangkaian lock kecil, bukan satu lock besar, menyalin page secara bertahap, dan mengulang penyalinan page yang berubah selama proses berlangsung.

Hasilnya adalah database SQLite yang bisa langsung dipakai. Buka seperti database lainnya:

sqlite3 backup.db
sqlite> .tables

Kamu juga bisa melakukan semuanya dalam satu perintah shell, yang biasanya menjadi bentuk akhir sebuah cron job:

sqlite3 app.db ".backup '/var/backups/app-$(date +%Y%m%d).db'"

Satu file masuk, satu file keluar. Tidak ada proses dump lalu restore, tidak ada parsing SQL: hanya page yang disalin di lapisan penyimpanan.

VACUUM INTO untuk Salinan yang Dipadatkan

VACUUM INTO adalah alat yang mirip tapi berbeda. Ia menulis salinan database yang baru dibangun ke file baru:

Hasilnya adalah database yang sama secara logis, tapi ditulis ulang dari awal: setiap page tersusun rapat, tanpa fragmentasi, tanpa page kosong sisa baris yang dihapus. Dengan begitu, file backup jadi sekecil mungkin.

Kapan memilih yang mana:

  • .backup: backup rutin yang sering. Lebih cepat, tidak bermasalah dengan penulis yang berjalan bersamaan, dan sama persis sampai ke byte.
  • VACUUM INTO: snapshot berkala saat kamu juga ingin file yang rapi dan berukuran minimum. Lebih lambat karena menulis ulang semuanya, dan memegang write lock pada database sumber selama berjalan.

Keduanya menghasilkan file .db yang valid dan bisa langsung dibuka.

Online Backup API dari Kode Aplikasi

Di dalam aplikasi, kamu tidak memanggil sqlite3 lewat shell. Kamu memakai online backup API yang disediakan driver-mu. Di sqlite3 bawaan Python, itu adalah Connection.backup:

import sqlite3

source = sqlite3.connect("app.db")
dest = sqlite3.connect("backup.db")

with dest:
    source.backup(dest)

source.close()
dest.close()

Method backup menyalin page dari source ke dest sementara koneksi lain tetap bekerja. Kamu juga bisa memberikan pages= untuk menyalin per potongan dan progress= untuk menerima callback. Ini berguna untuk database besar saat kamu ingin membatasi kecepatan penyalinan atau menampilkan progres.

Sebagian besar driver di bahasa lain menyediakan C API yang sama (sqlite3_backup_init, _step, _finish) dengan nama yang mirip. Polanya selalu sama: buka sumber, buka tujuan, salin page langkah demi langkah, selesaikan.

Backup Saat Database Sedang Dipakai

Di sinilah SQLite unggul tanpa banyak gembar-gembor. Baik .backup maupun online backup API dirancang untuk hot backup: database sumber boleh tetap terbuka dan aktif sepanjang waktu.

Yang sebenarnya terjadi:

  1. Backup mengambil shared lock dan mulai menyalin page.
  2. Kalau ada penulis yang mengubah page yang belum disalin, backup menyadarinya dan membacanya ulang.
  3. Penyalinan selesai begitu setiap page sudah konsisten.

Kamu tidak perlu menghentikan aplikasi, memutus koneksi, atau menjadwalkan downtime. Pada database yang sibuk, backup mungkin butuh beberapa putaran tambahan untuk tuntas, tapi pasti tuntas. File tujuan yang kamu dapat mewakili snapshot yang konsisten pada satu titik waktu.

Satu hal yang perlu diketahui: kalau kamu memakai mode WAL, sesekali jalankan PRAGMA wal_checkpoint(TRUNCATE); agar file WAL tidak membesar tanpa batas. Backup sendiri menangani WAL dengan benar; ini hanya kebiasaan baik umum untuk WAL.

Restore dari Backup

Me-restore database SQLite itu luar biasa membosankan, dan memang itulah intinya. File backup adalah database. Untuk memakainya, cukup buka:

sqlite3 backup.db
sqlite> SELECT COUNT(*) FROM notes;

Untuk me-restore di atas database yang sedang dipakai, misalnya untuk memulihkan data yang hilang, urutan yang aman adalah:

  1. Hentikan setiap proses yang membuka database.
  2. Hapus file app.db, app.db-wal, dan app.db-shm yang ada. File WAL/SHM sisa dari database lama akan membingungkan SQLite kalau dipasangkan dengan file utama hasil restore.
  3. Salin backup-mu ke tempatnya: cp backup.db app.db.
  4. Jalankan ulang aplikasimu.

File -wal dan -shm itu penting. Kalau kamu melewatkan langkah 2, SQLite mungkin mencoba menerapkan WAL usang di atas file utama hasil restore, dan kamu akan mendapat kerusakan atau data yang tercampur aneh.

Dari dalam CLI, ada juga perintah .restore, kebalikan dari .backup:

sqlite3 app.db
sqlite> .restore backup.db
sqlite> .quit

Perintah ini menimpa isi database yang sedang terhubung dengan isi backup.db. Ia memakai online backup API yang sama, hanya ke arah sebaliknya.

.dump Adalah Alat yang Berbeda

Kamu akan menemukan rujukan ke .dump di tutorial lama. Itu bukan backup dalam arti yang sama: ia menghasilkan file teks SQL berisi pernyataan CREATE dan INSERT:

sqlite3 app.db .dump > app.sql

Untuk me-restore, kamu menjalankan ulang SQL-nya:

sqlite3 new.db < app.sql

Ini berguna untuk migrasi antarversi SQLite, membandingkan skema di git, atau memindahkan data ke database engine lain. Cara ini lebih lambat, lebih besar, dan lebih berisiko kehilangan informasi dibanding .backup (collation kustom, generated column, dan beberapa pragma bisa butuh perhatian ekstra). Untuk backup sungguhan dari database yang sedang dipakai, pilih .backup atau VACUUM INTO.

Rutinitas Backup yang Masuk Akal

Untuk sebagian besar aplikasi, kombinasi ini bekerja dengan baik:

  • .backup yang dijadwalkan: per jam, per hari, sesuai seberapa banyak data yang boleh hilang. Murah, cepat, dan bisa berjalan saat database aktif.
  • VACUUM INTO mingguan ke path terpisah. Menangkap penyimpangan, memberimu snapshot yang dipadatkan, dan menguji jalur kode yang berbeda.
  • Kebijakan retensi: simpan N backup harian terakhir dan M backup mingguan terakhir. Database SQLite bisa dikompresi dengan baik, jadi menjalankan gzip backup.db setelahnya layak dilakukan.
  • Sesekali restore salah satu backup dan jalankan beberapa query terhadapnya. Backup yang belum pernah diuji hanyalah harapan, bukan backup.
# Daily, in cron:
sqlite3 /var/lib/app/app.db ".backup '/var/backups/app-$(date +%F).db'"
gzip "/var/backups/app-$(date +%F).db"

# Weekly:
sqlite3 /var/lib/app/app.db "VACUUM INTO '/var/backups/app-weekly-$(date +%F).db'"

Kedua perintah aman dijalankan saat aplikasi sedang melayani request.

Berikutnya: Pengaturan PRAGMA

Backup adalah salah satu urusan operasional, dan mengatur perilaku saat runtime adalah urusan lainnya. SQLite menyediakan pengaturannya lewat pernyataan PRAGMA: journal mode, tingkat synchronous, ukuran cache, penegakan foreign key. Halaman berikutnya membahas yang perlu kamu tahu.

Pertanyaan yang sering diajukan

Bagaimana cara backup database SQLite?

Dari CLI, jalankan .backup path/to/backup.db saat terhubung ke database sumber. Dari kode aplikasi, pakai online backup API (sqlite3_backup_init di C, atau padanannya di driver bahasa yang kamu pakai). Keduanya menghasilkan salinan yang konsisten meskipun koneksi lain sedang menulis.

Bisakah saya menyalin file .db begitu saja sebagai backup?

Hanya kalau kamu yakin tidak ada proses yang membuka database untuk menulis. Kalau tidak, kamu bisa menyalin file di tengah transaksi dan berakhir dengan backup yang rusak, atau kehilangan data yang masih ada di file WAL. Pakai .backup atau VACUUM INTO sebagai gantinya, karena keduanya menangani lock dan isi WAL dengan benar.

Apa bedanya .backup dan VACUUM INTO?

.backup memakai online backup API dan menghasilkan salinan yang sama persis sampai ke tingkat byte, termasuk page yang tidak terpakai. VACUUM INTO 'file.db' menulis salinan yang baru dipadatkan: lebih kecil dan bebas fragmentasi, tapi setiap page ditulis ulang. Pakai .backup untuk backup rutin, dan VACUUM INTO kalau kamu juga ingin mengambil kembali ruang.

Bagaimana cara restore database SQLite dari file backup?

Kalau backup-nya berupa file .db, cukup buka file itu, karena database SQLite adalah satu file. Untuk me-restore di atas database yang sudah ada, hentikan aplikasimu, ganti file-nya (dan hapus file -wal/-shm yang tersisa), lalu buka kembali. Dari CLI, kamu juga bisa menjalankan .restore path/to/backup.db saat terhubung ke database baru.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai