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.
Dampak awal yang terlihat dari sisi situs
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.
Urutan investigasi dari disk ke tabel
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 20SQL
-- 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.
Temuan kunci: tidak semua pesan crashed berarti tabel asli rusak
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.
Mitigasi sementara: kosongkan ruang, amankan salinan, baru repair
- Kosongkan ruang dulu sampai lega, bukan sekadar beberapa ratus MB. Cari penyebab disk penuh (log, backup lama, binary log, cache) dan bereskan.
- Buat salinan file tabel yang rusak sebelum repair. Untuk MyISAM, file
.frm,.MYD, dan.MYIada di direktori database di dalamdatadir. Paling aman disalin saat service MySQL berhenti. Kalau tidak memungkinkan, minimal hentikan dulu akses tulis ke tabel itu. - Catat jumlah baris yang masih bisa dibaca, misalnya dengan
SELECT COUNT(*), kalau query itu masih berjalan. - Jalankan repair per tabel, bukan langsung ke semua database.
- 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_optionsREPAIR 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.
Kapan restore lebih aman daripada repair
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 jangka panjang supaya tidak terulang
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
datadirke 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.
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.