Kenapa Kolom Database Tidak Bisa Langsung Dihapus

Tim Anda baru saja selesai memperbarui kode aplikasi untuk menggunakan skema database baru. Kolom lama sudah tidak terpakai dan terlihat seperti sampah. Anda ingin membersihkannya. Maka Anda hapus kolom tersebut.

Beberapa menit kemudian, error mulai membanjiri log. Pengguna melaporkan bahwa fitur yang mereka gunakan lima menit lalu kini menampilkan halaman kosong. Seseorang dari shift malam menelepon karena batch job yang berjalan tengah malam baru saja crash. Anda menghabiskan dua jam berikutnya untuk mencari tahu apa yang salah.

Skenario ini terjadi di tim dengan berbagai ukuran. Keinginan untuk langsung menghapus skema lama memang bisa dimengerti, tetapi di sistem produksi, hal ini hampir selalu berakibat buruk. Berikut penjelasannya.

Instance Lama Masih Berjalan

Alasan paling umum mengapa penghapusan skema gagal adalah karena belum semua instance aplikasi diperbarui. Di produksi, deployment berlangsung secara bertahap. Anda memperbarui satu server, lalu server berikutnya, lalu berikutnya lagi. Selama jeda itu, beberapa server masih menjalankan kode lama.

Ketika instance lama mencoba membaca atau menulis ke kolom yang sudah tidak ada, database mengembalikan error. Error itu menjadi request yang gagal. Request yang gagal itu menjadi keluhan pengguna. Masalahnya bukan pada kode baru, melainkan pada celah waktu antara langkah-langkah deployment.

Bahkan jika Anda menggunakan blue-green deployment atau canary release, prinsip yang sama berlaku: pada titik mana pun selama peluncuran, beberapa versi aplikasi Anda masih hidup. Semuanya berbagi database yang sama. Jika skema berubah sebelum semua instance menyesuaikan, sesuatu akan rusak.

Migrasi Data Jarang Instan

Masalah kedua adalah data. Kolom dan tabel lama seringkali masih menyimpan data yang belum dipindahkan ke struktur baru. Mungkin skrip migrasi berhasil di staging, tetapi di produksi ukuran dataset sepuluh kali lebih besar. Mungkin ada relasi foreign key yang perlu verifikasi manual. Mungkin migrasi itu sendiri memakan waktu berjam-jam dan tidak bisa diselesaikan dalam satu jendela pemeliharaan.

Jika Anda menghapus skema sebelum semua data dimigrasi, data itu akan hilang. Memulihkannya berarti mengembalikan dari backup, yang menyebabkan downtime dan berisiko kehilangan data yang ditulis setelah backup diambil. Untuk tabel dengan volume tulis tinggi, celah itu bisa signifikan.

Beberapa tim berasumsi mereka bisa memigrasi data di langkah terpisah sebelum menghapus skema. Itu berhasil secara teori, tetapi dalam praktiknya, kasus tepi selalu muncul. Sebuah job terjadwal yang tidak diingat siapa pun, query pelaporan yang berjalan sebulan sekali, integrasi lawas yang hanya aktif dalam kondisi tertentu. Konsumen tersembunyi dari skema lama ini baru terlihat setelah kolom dihapus.

Dependensi Tersembunyi Ada di Mana-Mana

Ini membawa kita ke masalah terberat: dependensi yang tidak diketahui. Tidak semua konsumen skema database Anda terdokumentasi. Tidak semua konsumen bahkan merupakan aplikasi yang Anda kendalikan.

Pertimbangkan skenario berikut:

  • Batch job yang ditulis tim lain berjalan setiap malam dan membaca dari tabel yang akan Anda hapus.
  • Alat pelaporan melakukan query ke kolom lama untuk dashboard yang sudah tidak dirawat siapa pun.
  • Skrip monitoring memeriksa tabel tertentu untuk memverifikasi kesegaran data.
  • Integrasi pihak ketiga mengirim data ke endpoint yang menulis ke skema lama.

Tak satu pun dari ini terlihat di kode aplikasi Anda. Tak satu pun akan muncul dalam grep repositori Anda. Mereka baru terlihat ketika rusak.

Bagian terburuknya adalah beberapa kegagalan ini bersifat diam-diam. Query yang mereferensi kolom yang dihapus mungkin tidak langsung crash. Ia mungkin mengembalikan nilai NULL atau himpunan hasil kosong, dan sistem konsumen mungkin menafsirkannya sebagai data yang valid. Anda berakhir dengan laporan yang korup, dashboard yang salah, atau pipeline data yang diam-diam menghasilkan output yang keliru. Saat ada yang menyadarinya, akar masalah sudah terkubur di bawah lapisan pemrosesan hilir.

Perubahan Irreversibel Memperbesar Risiko

Masalah fundamental dengan menghapus skema secara langsung adalah bahwa tindakan itu irreversibel. Begitu kolom atau tabel hilang, satu-satunya cara untuk mengembalikannya adalah dengan restore database penuh. Itu berarti downtime. Itu berarti potensi kehilangan data. Itu berarti tim Anda berada di bawah tekanan untuk memperbaiki sesuatu dengan cepat, yang justru menjadi saat kesalahan terjadi.

Bandingkan dengan menambahkan kolom baru. Menambahkan bersifat reversibel: jika ada yang salah, Anda bisa menghapus kolom yang baru ditambahkan. Menghapus tidak. Begitu Anda berkomitmen untuk menghapus, Anda telah berkomitmen pada jalur tanpa rollback yang mudah.

Asimetri inilah mengapa tim berpengalaman memperlakukan penghapusan skema sebagai proses multi-langkah, bukan tindakan tunggal. Mereka tidak menghapus skema lama sampai yakin bahwa setiap konsumen telah bermigrasi. Dan mereka membangun keyakinan itu melalui observasi, bukan asumsi.

Pendekatan yang Lebih Aman: Expand Lalu Contract

Alih-alih menghapus skema lama dan berharap tidak ada yang rusak, ada pola yang lebih baik. Pola ini memiliki dua fase.

Diagram alir di bawah membandingkan dua jalur tersebut.

flowchart TD A["Ingin menghapus kolom?"] --> B{"Instance lama masih berjalan?"} B -->|"Ya"| C["Gunakan expand-contract"] B -->|"Tidak"| D{"Ada dependensi tersembunyi?"} D -->|"Ya"| C D -->|"Tidak"| E["Hapus langsung"] E --> F["Risiko: error, kehilangan data, rollback tidak mungkin"] C --> G["Tambah kolom baru"] G --> H["Backfill data"] H --> I["Tulis ganda ke kedua kolom"] I --> J["Alihkan baca ke kolom baru"] J --> K["Pantau untuk masalah"] K --> L["Hapus kolom lama"]

Pertama, expand: tambahkan kolom atau tabel baru sambil mempertahankan yang lama. Kedua struktur ada secara bersamaan. Kode aplikasi diperbarui untuk menulis ke keduanya, atau membaca dari yang baru sambil fallback ke yang lama jika diperlukan. Selama fase ini, Anda memantau error, memverifikasi bahwa data ditulis dengan benar, dan mengonfirmasi bahwa semua konsumen menggunakan struktur baru.

Kedua, contract: setelah Anda memiliki bukti bahwa tidak ada yang bergantung pada skema lama, hapus skema tersebut. Ini bukan tebakan. Anda memiliki log, metrik, dan analisis query yang menunjukkan bahwa kolom lama tidak pernah diakses selama periode yang wajar. Baru setelah itu Anda menghapusnya.

Pola ini disebut expand-contract, dan ini adalah pendekatan standar untuk melakukan perubahan skema yang tidak kompatibel ke belakang dengan aman. Prosesnya memang lebih lama, tetapi mencegah insiden produksi yang mengubah pembersihan sederhana menjadi sesi debugging darurat seluruh tim.

Cuplikan SQL berikut membandingkan penghapusan satu langkah yang berisiko dengan proses multi-langkah yang lebih aman.

-- TIDAK AMAN: menghapus kolom secara langsung
ALTER TABLE users DROP COLUMN old_plan;

-- LEBIH AMAN: pendekatan expand-contract

-- Langkah 1: Tambah kolom baru
ALTER TABLE users ADD COLUMN new_plan VARCHAR(50);

-- Langkah 2: Backfill data dari kolom lama ke kolom baru
UPDATE users SET new_plan = old_plan WHERE new_plan IS NULL;

-- Langkah 3: Perbarui aplikasi untuk menulis ke kedua kolom
-- (ditangani di kode, bukan SQL)

-- Langkah 4: Setelah memastikan tidak ada baca ke kolom lama, hapus
ALTER TABLE users DROP COLUMN old_plan;

Daftar Periksa Praktis Sebelum Menghapus Skema

Sebelum Anda menghapus kolom atau tabel apa pun, verifikasi kondisi berikut:

  • Semua instance aplikasi telah menjalankan kode baru setidaknya selama satu siklus deployment penuh.
  • Tidak ada query yang mereferensi skema lama di produksi setidaknya selama satu minggu.
  • Semua batch job, laporan, dan integrasi yang mungkin menggunakan skema lama telah diperbarui atau dinonaktifkan.
  • Migrasi data selesai dan terverifikasi, termasuk catatan historis.
  • Rencana rollback ada yang tidak memerlukan restore database penuh.

Jika salah satu kondisi ini tidak terpenuhi, Anda belum siap untuk menghapus.

Kesimpulan

Menghapus kolom database bukanlah tugas pembersihan. Ini adalah perubahan produksi dengan konsekuensi irreversibel. Cara aman untuk melakukannya adalah dengan mempertahankan skema lama sampai Anda memiliki bukti bahwa tidak ada yang membutuhkannya lagi. Bukti itu membutuhkan waktu untuk dikumpulkan, tetapi itu adalah satu-satunya cara untuk menghindari telepon larut malam tentang fitur yang rusak padahal sebelumnya berfungsi dengan baik.