Bali, Indonesia
Insights

Tabel MySQL Ditandai Crashed Setelah Disk Penuh, Perbaiki atau Restore?

November 1, 2026
0:00
Disk server sempat penuh. Ruangnya sudah dibersihkan, tapi situs masih error. Di log atau di layar muncul pesan Table '...' is marked as crashed and should be repaired, dan beberapa halaman kosong atau datanya tidak lengkap. Pertanyaan yang biasanya langsung muncul: cukup jalankan REPAIR TABLE, atau harus restore dari backup? Jawabannya tergantung engine tabel, seberapa parah kerusakannya, dan seberapa penting data yang mungkin hilang. Tulisan ini disusun seperti post-mortem: dampak awal, urutan investigasi, temuan kunci, mitigasi sementara, lalu perbaikan jangka panjang. Skenarionya pola umum yang sering muncul, bukan cerita insiden tertentu.
Tabel yang ditandai crashed tidak selalu membuat seluruh situs mati. Query ke tabel itu gagal, sementara tabel lain tetap bisa dibaca. Di WordPress, misalnya, kalau yang rusak wp_options, hampir semua halaman ikut error karena tabel itu dibaca di setiap request. Kalau yang rusak tabel log plugin atau tabel statistik, situs mungkin terlihat normal dan hanya fitur tertentu yang gagal. Di meja support, hal yang sering membingungkan pelanggan adalah ini: disk sudah lega, kenapa masih error? Mengosongkan disk tidak membatalkan apa yang sudah terjadi saat disk penuh. Kalau ada proses tulis ke file tabel yang gagal di tengah jalan, file itu tetap dalam kondisi setengah jadi sampai diperbaiki atau diganti.
Langkah pertama adalah memastikan ruang benar-benar sudah cukup, termasuk inode. Inode adalah slot metadata file di filesystem. Disk bisa terlihat masih punya ruang, tapi kalau inode habis, file baru tetap tidak bisa dibuat. Setelah itu, cek juga di mana MySQL menyimpan data dan file sementaranya, karena keduanya bisa berada di partisi yang berbeda.
BASH
# Lokasi data dan file sementara MySQL/MariaDB
mysql -e 'SELECT @@datadir, @@tmpdir;'

# Sisa ruang dan inode di partisi tersebut
df -h /var/lib/mysql /tmp
df -i /var/lib/mysql /tmp

# Cari pesan crashed di error log (lokasi log tergantung distro dan konfigurasi)
sudo grep -i 'crashed' /var/log/mysql/error.log | tail -n 20
Langkah kedua adalah mencari tahu tabel mana saja yang terdampak dan apa engine-nya. Engine adalah komponen yang benar-benar menyimpan data di disk. Di MySQL dan MariaDB, yang paling umum adalah InnoDB, MyISAM, dan (khusus MariaDB) Aria. Ini penting karena cara memperbaikinya berbeda total.
SQL
-- Daftar tabel dan engine-nya di satu database
SELECT TABLE_NAME, ENGINE
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'nama_database';

-- Cek satu tabel (read-only, tidak mengubah data)
CHECK TABLE nama_database.wp_options;
CHECK TABLE akan melaporkan status tabel. Kalau hasilnya OK, tabel itu tidak perlu disentuh. Kalau ada pesan error atau warning, catat nama tabelnya untuk langkah berikutnya.
Bagian ini sering terlewat. Ada dua pola yang harus dibedakan sebelum melakukan apa pun. Pola pertama: pesan error menyebut path di direktori sementara, misalnya Incorrect key file for table '/tmp/#sql_xxxx.MYI'; try to repair it. Nama file yang diawali #sql di tmpdir adalah temporary table, yaitu tabel sementara yang dibuat MySQL saat menjalankan query berat seperti GROUP BY atau ORDER BY pada data besar. Yang penuh adalah partisi tempat file sementara itu ditulis, bukan tabel milik situs. Begitu ruang di tmpdir cukup, error ini biasanya hilang sendiri tanpa repair apa pun. Menjalankan repair ke tabel asli dalam kasus ini tidak ada gunanya. Pola kedua: pesan menyebut tabel asli di database situs. Di sini engine menentukan segalanya. Status marked as crashed adalah konsep milik MyISAM dan Aria. Pada MyISAM, data dan index disimpan di file terpisah (.MYD dan .MYI), dan tidak ada transaction log untuk mengembalikan perubahan yang setengah jadi. Setiap kali tabel dibuka untuk ditulis, MyISAM menaikkan penanda di header file index, lalu menurunkannya saat tabel ditutup dengan benar. Kalau penulisan gagal karena disk penuh, atau proses berhenti di tengah, penanda itu tertinggal dan isi data bisa tidak sinkron dengan index. Pada pembukaan berikutnya, MySQL melihat kondisi itu dan menandai tabel sebagai crashed. InnoDB bekerja dengan cara lain. Perubahan dicatat dulu di redo log, dan saat service start ulang, InnoDB menjalankan crash recovery untuk menyelesaikan atau membatalkan transaksi yang belum tuntas. Karena itu, tabel InnoDB biasanya tidak muncul dengan pesan marked as crashed. Kalau InnoDB benar-benar rusak, gejalanya lain: service gagal start, atau error log berisi pesan tentang page yang korup. REPAIR TABLE juga tidak berlaku untuk InnoDB, dan hasilnya hanya pesan bahwa engine tersebut tidak mendukung repair.
Urutannya penting. Repair MyISAM membangun ulang index dan kadang file data, dan proses itu butuh ruang kosong yang cukup, sering kira-kira sebesar tabelnya sendiri. Repair yang dijalankan saat disk masih nyaris penuh bisa gagal di tengah dan membuat kondisinya lebih buruk. Urutan yang aman untuk tabel MyISAM atau Aria:
  1. Kosongkan ruang dulu sampai lega, bukan sekadar beberapa ratus MB. Cari penyebab disk penuh (log, backup lama, binary log, cache) dan bereskan.
  2. Buat salinan file tabel yang rusak sebelum repair. Untuk MyISAM, file .frm, .MYD, dan .MYI ada di direktori database di dalam datadir. Paling aman disalin saat service MySQL berhenti. Kalau tidak memungkinkan, minimal hentikan dulu akses tulis ke tabel itu.
  3. Catat jumlah baris yang masih bisa dibaca, misalnya dengan SELECT COUNT(*), kalau query itu masih berjalan.
  4. Jalankan repair per tabel, bukan langsung ke semua database.
  5. Bandingkan jumlah baris sesudah repair, lalu cek fungsi situs yang memakai tabel itu.
BASH
# Cek semua tabel di satu database (read-only)
mysqlcheck --check nama_database

# Repair satu tabel MyISAM/Aria, hanya setelah salinan file aman
mysqlcheck --repair nama_database wp_options
Perintah yang sama bisa dijalankan dari dalam MySQL dengan REPAIR TABLE nama_tabel;. Hasilnya setara. Peringatan: repair bisa membuang baris yang tidak bisa dibaca supaya tabel kembali konsisten. Artinya tabel bisa kembali OK tapi isinya berkurang tanpa pesan yang mencolok. Itu sebabnya langkah membandingkan jumlah baris tidak boleh dilewati. Hindari juga menjalankan myisamchk langsung ke file tabel saat MySQL masih berjalan, karena dua proses yang menulis file yang sama bisa merusak tabel lebih jauh. Opsi USE_FRM pada REPAIR TABLE juga sebaiknya hanya dipakai kalau sudah paham risikonya, karena opsi itu membangun ulang index dari definisi tabel dan bisa memperburuk keadaan kalau versinya tidak cocok.
Repair cocok kalau tabelnya MyISAM atau Aria, CHECK TABLE sesudah repair menghasilkan OK, dan jumlah baris sebelum dan sesudah sama atau selisihnya bisa diterima. Tabel cache, log, atau statistik masuk kategori ini, karena kehilangan beberapa baris di sana tidak berdampak besar. Restore lebih masuk akal di beberapa kondisi berikut. Pertama, repair gagal, atau pesan berubah menjadi marked as crashed and last (automatic?) repair failed. Kedua, jumlah baris turun di tabel yang isinya penting, seperti pesanan, pengguna, atau transaksi. Di situ setiap baris yang hilang adalah data nyata, dan kamu tidak tahu persis baris mana yang hilang. Ketiga, tabelnya InnoDB dan service gagal start atau error log melaporkan page korup. Untuk InnoDB, jalur daruratnya adalah parameter innodb_force_recovery di file konfigurasi, yang memaksa service start dalam mode terbatas supaya data masih bisa di-dump. Parameter ini alat penyelamat sementara, bukan perbaikan. Level yang lebih tinggi makin berisiko, jadi baca dokumentasi versi yang kamu pakai dulu. Restore juga tidak harus semuanya atau tidak sama sekali. Pendekatan yang biasanya lebih aman: restore backup ke database terpisah, bandingkan isinya dengan tabel hasil repair, lalu ambil hanya yang dibutuhkan. Kalau binary log aktif dan masih tersimpan, data sesudah waktu backup kadang bisa diputar ulang. Cara ini butuh kehati-hatian dan di luar cakupan tulisan ini.
Perbaikan paling efektif adalah tidak memakai MyISAM untuk data aplikasi. Banyak instalasi lama masih punya tabel MyISAM karena dibuat saat itu masih default, atau karena plugin membuat tabel dengan engine tertentu. Konversi dengan ALTER TABLE nama_tabel ENGINE=InnoDB; membuat tabel mendapat crash recovery. Konversi ini menulis ulang seluruh tabel, jadi butuh ruang kosong, bisa mengunci tabel selama prosesnya, dan perlu dicek kompatibilitas fiturnya (misalnya index FULLTEXT di versi lama). Lakukan di jam sepi, setelah backup. Selain itu:
  • Pasang monitoring disk dan inode dengan alert yang berbunyi jauh sebelum penuh, bukan saat sudah penuh.
  • Kalau memungkinkan, pisahkan datadir ke partisi sendiri supaya log atau upload yang membengkak tidak ikut memakan ruang database.
  • Atur retensi binary log. Nama variabelnya berbeda antara versi MySQL dan MariaDB, jadi cek dokumentasi versi yang dipakai.
  • Batasi ukuran log sistem. Kalau journald ikut berkontribusi, catatan di Practical Notes on Minimizing ram and disk used by systemd-journald bisa jadi titik awal.
  • Uji restore backup secara rutin. Backup yang belum pernah dicoba di-restore belum terbukti bisa dipakai.
Kalau ketemu pesan marked as crashed setelah disk penuh, jangan langsung repair semua tabel. Pastikan ruang sudah lega, cek apakah error-nya dari temporary table di tmpdir, lihat engine tabelnya, salin file tabel, baru repair satu per satu dan bandingkan jumlah baris. Untuk tabel cache atau log, repair biasanya cukup. Untuk data yang tidak boleh hilang, atau untuk InnoDB yang benar-benar korup, restore dari backup ke database terpisah lalu bandingkan isinya adalah jalan yang lebih aman.