Pindah database adalah keputusan rekayasa, bukan pertaruhan gengsi. Sepanjang course ini kita telah mengukur batas SQLite dengan angka nyata; dua chapter sebelumnya menyiapkan pola produksi untuk bekerja di dalam batas itu. Chapter penutup ini mengajukan pertanyaan yang berbeda: bagaimana mengenali saat batas itu benar-benar terlampaui, kapan justru tidak, dan bagaimana proses pindahnya bila memang harus dilakukan.
Sinyal untuk Tetap #
Empat kondisi ini membuat pindah jadi langkah yang tidak perlu. Pertama, arsitektur kita memang satu mesin — embedded, aplikasi desktop, atau satu server aplikasi. Kedua, beban didominasi pembacaan, wilayah yang paling disukai SQLite karena pembaca tidak saling menghalangi. Ketiga, tim kecil tanpa operator database: tanpa server, tidak ada proses yang harus diamankan, dituning, di-upgrade, dan dimonitor tersendiri. Keempat, kesederhanaan bernilai nyata — satu berkas yang bisa disalin dengan scp dan langsung dibuka di mesin mana pun.
Pemetaan lengkap skenario ini ada di Chapter Kapan Menggunakan SQLite. Yang perlu ditambahkan di sini: bertahan adalah keputusan aktif, bukan kemalasan. Bila tidak satu pun sinyal pindah di bawah terpenuhi, bertahan adalah pilihan yang tepat.
Sinyal untuk Pindah #
| Sinyal | Kenapa SQLite mulai tersulit | Yang dicari di database server |
|---|---|---|
| Kontensi tulis berkelanjutan | galat database is locked makin sering meski WAL, busy_timeout, retry, dan batching sudah diterapkan | banyak penulis sungguhan yang paralel |
| Skala horizontal | beberapa mesin aplikasi harus menulis ke data yang sama; berkas di network filesystem berbahaya | protokol jaringan sebagai jalan masuk tunggal |
| Dataset dan jendela operasi | backup, VACUUM, dan pemulihan makin lama seiring membesarnya satu berkas | data tersebar lintas volume |
| Fitur sisi server | izin per-pengguna, stored procedure, replikasi bawaan tidak ada | semuanya adalah fitur produk |
Baris pertama adalah sinyal paling jujur: ia baru sah bila strategi Chapter Strategi Concurrency sudah diterapkan penuh dan galat tetap muncul pada jam sibuk. Kalau busy_timeout masih 0 atau transaksi masih panjang, yang perlu diperbaiki adalah aplikasinya, bukan databasenya. Batas 281 terabyte dari Chapter Format Berkas Database bukan angka praktis — yang praktis terasa adalah lamanya jendela pemeliharaan.
Rumput Tetangga Lebih Hijau #
Kerangka pikir yang sehat: pindahlah untuk fitur yang benar-benar dibutuhkan — bukan karena mitos. Daftar sinyal di atas adalah alat ujinya.
Jalur Migrasi #
Ekspor dengan .dump #
Titik berangkat paling sederhana adalah .dump, yang menuliskan seluruh database sebagai skrip SQL — persis seperti yang dibahas pada Chapter Backup dan Restore. Kita buat contoh dengan satu tabel ber-AUTOINCREMENT:
rm -f toko.db
sqlite3 toko.db "CREATE TABLE pelanggan (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nama TEXT NOT NULL,
email TEXT NOT NULL
);
INSERT INTO pelanggan (nama, email) VALUES
('Budi', '[email protected]'),
('Siti', '[email protected]'),
('Ani', '[email protected]');"
sqlite3 toko.db .dump > toko.sql
cat toko.sqlOutput yang Dihasilkan:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE pelanggan (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nama TEXT NOT NULL,
email TEXT NOT NULL
);
INSERT INTO pelanggan VALUES(1,'Budi','[email protected]');
INSERT INTO pelanggan VALUES(2,'Siti','[email protected]');
INSERT INTO pelanggan VALUES(3,'Ani','[email protected]');
INSERT INTO sqlite_sequence VALUES('pelanggan',3);
COMMIT;Baris-baris itu tidak semuanya langsung jalan di PostgreSQL atau MySQL. Tiga penyesuaian yang pasti dibutuhkan:
PRAGMA foreign_keys=OFF;— perintahPRAGMAtidak dikenal database server; hapus baris ini.- Kata kunci
AUTOINCREMENT— ganti menjadiGENERATED BY DEFAULT AS IDENTITYpada PostgreSQL atauAUTO_INCREMENTpada MySQL. Tanpa penyesuaian ini, kolomiddi tujuan tidak akan menghasilkan angka otomatis untuk baris baru. INSERT INTO sqlite_sequence ...— tabel internal pencatat nomor terpakai (dibahas pada Chapter Constraint pada Tabel) tidak ada di database server; hapus barisnya.
Baris BEGIN TRANSACTION, CREATE TABLE, dan seluruh INSERT data umumnya berpindah tanpa perubahan — gaya kutip dan pemisah nilainya sama. Untuk dataset yang lebih besar atau lintas format, Chapter Export dan Import Data menyediakan jalur CSV.
Audit Tipe sebelum Pindah #
Jebakan yang lebih halus dari sintaks adalah type affinity: kolom INTEGER pada SQLite biasa tetap menerima teks yang tidak bisa dikonversi, dan PostgreSQL akan menolaknya saat proses muat. Audit isi dengan typeof() sebelum ekspor:
sqlite3 toko.db "CREATE TABLE stok (id INTEGER PRIMARY KEY, produk TEXT NOT NULL, jumlah INTEGER);
INSERT INTO stok VALUES
(1, 'Kopi Gayo 200g', 40),
(2, 'Teh Hijau 100g', 'dua puluh'),
(3, 'Gula Aren 500g', 12),
(4, 'Teh Melati 100g', NULL),
(5, 'Kopi Tubruk 250g', 'banyak');"
sqlite3 toko.db "SELECT id, produk, jumlah, typeof(jumlah) FROM stok ORDER BY id;"
sqlite3 toko.db "SELECT id, produk, jumlah FROM stok WHERE typeof(jumlah) = 'text' ORDER BY id;"
sqlite3 toko.db "SELECT id, CAST(jumlah AS INTEGER) AS hasil_cast FROM stok WHERE id IN (2, 5) ORDER BY id;"Output yang Dihasilkan:
1|Kopi Gayo 200g|40|integer
2|Teh Hijau 100g|dua puluh|text
3|Gula Aren 500g|12|integer
4|Teh Melati 100g||null2|Teh Hijau 100g|dua puluh
5|Kopi Tubruk 250g|banyak2|0
5|0Tiga keluaran itu membentuk satu kesimpulan. Query pertama memperlihatkan isi yang tidak pernah diperbolehkan server database mana pun: teks 'dua puluh' dan 'banyak' duduk di kolom INTEGER. Query kedua adalah daftar kerja pembersihannya. Query ketiga menegaskan CAST bukan solusi — teks yang bukan angka menjadi 0, nilai yang sah untuk stok, sehingga perbaikannya harus manual baris demi baris. Untuk data baru, tabel STRICT dari Chapter Tipe Data dan Type Affinity mencegah masalah ini sejak awal.
Perilaku PRAGMA yang Tidak Ikut Pindah #
journal_mode, synchronous, dan busy_timeout adalah kenop perilaku berkas milik SQLite — database server punya model konfigurasi yang berbeda dan tidak memilikinya. Yang perlu diuji ulang pasca-migrasi adalah perilaku, bukan angkanya: misalnya foreign_keys yang di SQLite harus dinyalakan per-koneksi (dibahas pada Chapter Foreign Key) sedangkan server umumnya menegakkannya sejak awal.
Daftar Periksa Keputusan #
| Pertanyaan | Menunjuk pindah bila | Menunjuk bertahan bila |
|---|---|---|
| Berapa mesin yang perlu menulis ke data yang sama? | lebih dari satu | satu |
Apakah galat database is locked tetap sering setelah seluruh strategi concurrency diterapkan? | ya | tidak |
| Ke arah mana beban bergerak? | tulisan terus bertambah | baca dominan, stabil |
| Apakah klien lintas jaringan perlu akses langsung? | ya | semua lewat aplikasi |
| Apakah butuh izin per-pengguna di level database? | ya | cukup di lapisan aplikasi |
| Siapa yang mengurus operasionalnya? | tim punya operator database | tim tanpa operator |
Jawaban yang menunjuk pindah mengharuskan kita jujur menyiapkan tenaga operasionalnya. Sisanya — mayoritas sistem yang kita bangun sehari-hari — justru menikmati keringkasan SQLite: satu berkas, tanpa server, dengan batas yang sudah kita pahami dan kelola sepanjang course ini.