Strategi Backup

.backup, VACUUM INTO, dan penyalinan berkas yang aman.

Daftar isi

Pembuatan cadangan (backup) diperlukan sebelum pembaruan besar, pemindahan mesin, atau sebagai arsip rutin basis data. SQLite menyediakan beberapa cara yang masing-masing memiliki kondisi pemakaiannya, mulai dari perintah titik .backup, pernyataan VACUUM INTO, penyalinan berkas secara langsung, sampai API backup pada Python. Topik ini menetapkan kaidah kapan tiap cara dipakai, memeragakan .backup dan VACUUM INTO pada CLI beserta verifikasi isinya, dan menutup dengan cadangan terprogram lewat connection.backup.

Empat cara dan kaidah pemakaiannya#

Keempat cara berikut menghasilkan berkas basis data yang utuh dan dapat dibuka, tetapi keempatnya menuntut keadaan yang berbeda dari basis data sumbernya. .backup dan VACUUM INTO bekerja pada basis data yang sedang dipakai sekalipun, sedangkan penyalinan berkas langsung menuntut basis data yang tenang. Pemilihan cara mengikuti tiga kebutuhan yang saling menyesuaikan, yaitu kecepatan pembuatan, kerapian ukuran hasil, dan kesiapan basis data sumber pada saat cadangan diambil. Bagi cadangan berkala, nama berkas tujuan yang berbeda pada tiap pembuatan lebih mudah diurus daripada satu berkas yang ditimpa terus, sebab cadangan lama tetap tersedia bila versi terbarunya ternyata bermasalah. Keempat baris pada tabel berikut merangkum kaidahnya, termasuk API backup Python sebagai wujud terprogram dari .backup.

CaraAlatCocok untuk
.backupCLI atau programsalinan rutin yang cepat dari basis data hidup
VACUUM INTOCLI atau programsalinan terkompaksi dan arsip jangka panjang
Penyalinan berkascp atau program penyalinbasis data yang sedang tidak dipakai
connection.backupPythoncadangan terprogram dari aplikasi yang berjalan

Basis data contoh berikut dipakai sepanjang topik, dan tiga bukunya menjadi ukuran sederhana untuk memverifikasi isi setiap cadangan yang dihasilkan.

bash
# basis data contoh perpustakaan
sqlite3 perpustakaan.db <<'SQL'
CREATE TABLE buku (
  id      INTEGER PRIMARY KEY,
  judul   TEXT NOT NULL,
  penulis TEXT NOT NULL,
  tahun   INTEGER
);
INSERT INTO buku (judul, penulis, tahun) VALUES
  ('Kisah Kota Tua', 'Sari Wulandari', 2018),
  ('Anak Sungai', 'Rahmat Hidayat', 2021),
  ('Musim di Ujung Jalan', 'Lina Marlina', 2019);
SQL

.backup pada CLI#

Perintah titik .backup menyalin seluruh isi basis data sumber ke berkas tujuan secara konsisten, termasuk ketika basis data sumber sedang dipakai oleh program lain. Konsistensi ini diberikan oleh API backup internal SQLite yang membaca halaman demi halaman dengan penguncian yang benar, sehingga salinan tidak pernah berupa campuran dari dua keadaan yang berbeda. Perintahnya dijalankan dari dalam shell sqlite3 atau lewat argumen berisi perintah titik tersebut.

bash
# .backup menyalin isi basis data ke berkas baru secara konsisten
sqlite3 perpustakaan.db ".backup cadangan.db"
# isi salinan diverifikasi seperti basis data biasa
sqlite3 -header -column cadangan.db "SELECT count(*) AS jumlah_buku FROM buku;"
text Keluaran
jumlah_buku
-----------
          3

Hasil verifikasi menunjukkan tiga baris buku, sama dengan sumbernya, dan berkas cadangan.db sejak saat itu berdiri sendiri sebagai basis data utuh. Nama berkas tujuannya mengikuti aturan berkas biasa, yaitu jalur relatif terhadap direktori kerja atau jalur mutlak, sehingga cadangan dapat dituliskan ke folder arsip yang terpisah. Selama penyalinan berlangsung, basis data sumber tetap dapat melayani pembacaan dan penulisan, karena API backup bekerja halaman demi halaman dan menyesuaikan diri bila isinya berubah. Karena format salinannya sama persis dengan berkas sumber, salinan .backup dapat langsung dipakai menggantikan basis data yang rusak tanpa proses pemulihan tambahan. Cadangan semacam ini cocok dibuat sebelum setiap perubahan besar atau mengikuti jadwal tetap dari skrip operasional.

VACUUM INTO#

Pernyataan VACUUM INTO juga menulis salinan konsisten, tetapi salinannya disusun ulang dari nol, sehingga halaman kosong yang tertinggal dari baris yang pernah dihapus tidak ikut tersalin. Sifat ini menjadikannya pilihan untuk arsip jangka panjang dan untuk basis data yang ukurannya membengkak akibat penghapusan yang sering. Berkas tujuan harus belum ada, karena SQLite menolak menimpa berkas yang sudah terdapat di sana.

bash
# VACUUM INTO menulis salinan baru yang terkompaksi
sqlite3 perpustakaan.db "VACUUM INTO 'arsip.db'"
# isi arsip diverifikasi dengan SELECT
sqlite3 -header -column arsip.db "SELECT judul, tahun FROM buku ORDER BY id;"
text Keluaran
       judul          tahun
--------------------  -----
Kisah Kota Tua         2018
Anak Sungai            2021
Musim di Ujung Jalan   2019
bash
# VACUUM INTO menolak berkas tujuan yang sudah ada
sqlite3 perpustakaan.db "VACUUM INTO 'arsip.db'"
text Keluaran
Error in 2nd command line argument: output file already exists

Pesan error kedua muncul karena arsip.db sudah dibuat perintah sebelumnya, dan kegagalan semacam ini disengaja pada contoh untuk menegaskan aturannya. Penolakan tersebut melindungi cadangan lama agar tidak tertimpa tanpa sengaja, sedangkan pembaruan cadangan dilakukan dengan menghapus berkas lama terlebih dahulu atau menuliskan nama berkas yang memuat penanggalan. Pernyataan ini juga dapat dijalankan dari koneksi program apa pun tanpa perintah titik, sehingga aplikasi dapat membuat arsipnya sendiri dengan satu pernyataan SQL. Karena seluruh isi ditulis ulang, indeks ikut tersusun rapat dan ukuran berkas hasilnya mencerminkan data yang benar-benar ada. Perintah .backup berbeda sikapnya karena menimpa berkas tujuan tanpa pertanyaan.

Penyalinan berkas dan API backup Python#

Penyalinan berkas dengan cp hanya aman pada kondisi yang ketat, yaitu tidak ada transaksi yang sedang berjalan, tidak ada program lain yang menulis, dan tidak ada berkas jurnal pendamping seperti berkas -journal atau -wal di sebelah basis datanya. Salinan yang diambil di tengah transaksi dapat berupa berkas setengah jadi yang gagal dibuka. Untuk basis data yang sedang dipakai, API backup pada Python menjadi jalur yang tepat karena menghasilkan snapshot, yaitu potret isi basis data pada satu titik waktu yang konsisten.

Skrip berikut dipasang sebagai berkas utuh cadangkan.py pada bundle topik ini. Koneksi bernama penulis memegang satu penyisipan yang belum di-commit, sedangkan cadangan diambil lewat koneksi pembaca yang berbeda, persis keadaan basis data yang sedang hidup.

python cadangkan.py
import sqlite3

penulis = sqlite3.connect("perpustakaan.db")
penulis.execute(
    "INSERT INTO buku (judul, penulis, tahun)"
    " VALUES ('Laut Biru', 'Dewi Lestari', 2020)"
)

pembaca = sqlite3.connect("perpustakaan.db")
tujuan = sqlite3.connect("cadangan-py.db")
pembaca.backup(tujuan)
print("baris cadangan :", tujuan.execute("SELECT count(*) FROM buku").fetchone()[0])

penulis.commit()
print("baris sumber   :", pembaca.execute("SELECT count(*) FROM buku").fetchone()[0])

penulis.close()
pembaca.close()
tujuan.close()
text Keluaran
baris cadangan : 3
baris sumber   : 4

Keluaran itu menunjukkan dua hal sekaligus. Cadangan tetap berhasil dibuat meskipun koneksi lain sedang memegang transaksi tulis, dan isi cadangannya konsisten berupa tiga baris yang sudah tersimpan, bukan empat baris yang tercampur penyisipan setengah jadi. Setelah commit, basis data sumber berisi empat baris. Metode backup juga menerima parameter pages untuk menyalin bertahap, sehingga basis data yang besar tidak memblokir aplikasi terlalu lama dalam satu langkah.

Ringkasan#

  • .backup menghasilkan salinan konsisten dari basis data yang sedang dipakai dan menimpa berkas tujuan yang sudah ada.
  • VACUUM INTO menulis salinan terkompaksi tanpa halaman kosong dan menolak berkas tujuan yang sudah terdapat sebelumnya.
  • Penyalinan berkas langsung hanya aman tanpa transaksi berjalan dan tanpa berkas jurnal pendamping.
  • connection.backup pada Python menyalin snapshot konsisten dari aplikasi yang berjalan dan dapat menyalin bertahap lewat parameter pages.

Referensi#