Howto: Bersihkan mesin penyimpanan mysql InnoDB?

133

Apakah mungkin untuk membersihkan mesin penyimpanan mysql innodb sehingga tidak menyimpan data dari tabel yang dihapus?

Atau apakah saya harus membangun kembali database baru setiap saat?

Bryan Field
sumber
Apa yang membuat Anda berpikir bahwa MySQL menyimpan data dari tabel yang dihapus?
Robert Munteanu
1
Jika saya menjatuhkan sejumlah besar tabel, file penyimpanan InnoDB saya tidak menyusut
Bryan Field
2
@RobertMunteanu: lihat bugs.mysql.com/bug.php?id=1341
Max

Jawaban:

351

Berikut adalah jawaban yang lebih lengkap sehubungan dengan InnoDB. Ini sedikit proses yang panjang, tetapi bisa sepadan dengan usaha.

Ingatlah bahwa itu /var/lib/mysql/ibdata1adalah file tersibuk di infrastruktur InnoDB. Biasanya menampung enam jenis informasi:

Arsitektur InnoDB

Arsitektur InnoDB

Banyak orang membuat banyak ibdatafile dengan harapan untuk manajemen dan kinerja ruang disk yang lebih baik, namun kepercayaan itu keliru.

Bisakah saya lari OPTIMIZE TABLE?

Sayangnya, menjalankan OPTIMIZE TABLEterhadap tabel InnoDB yang disimpan dalam file ruang-tabel bersama ibdata1melakukan dua hal:

  • Membuat data tabel dan indeks berdekatan di dalamnya ibdata1
  • Membuat ibdata1tumbuh karena data yang berdekatan dan halaman indeks ditambahkan keibdata1

Namun Anda dapat, memisahkan Data Tabel dan Indeks Tabel dari ibdata1dan mengelolanya secara mandiri.

Dapatkah saya menjalankan OPTIMIZE TABLEdengan innodb_file_per_table?

Misalkan Anda untuk menambahkan innodb_file_per_tableke /etc/my.cnf (my.ini). Lalu bisakah Anda menjalankan OPTIMIZE TABLEsemua Tabel InnoDB?

Kabar Baik : Ketika Anda menjalankan OPTIMIZE TABLEdengan innodb_file_per_tablediaktifkan, ini akan menghasilkan .ibdfile untuk tabel itu. Misalnya, jika Anda memiliki tabel mydb.mytabledengan datadir /var/lib/mysql, itu akan menghasilkan yang berikut:

  • /var/lib/mysql/mydb/mytable.frm
  • /var/lib/mysql/mydb/mytable.ibd

The .ibdakan berisi Pages Data dan Indeks Pages untuk meja itu. Bagus.

Berita Buruk : Yang Anda lakukan hanyalah mengekstrak Halaman Data dan Halaman Indeks mydb.mytabledari saat tinggal di ibdata. Entri kamus data untuk setiap tabel, termasuk mydb.mytable, masih tetap ada dalam kamus data (Lihat Representasi Pictorial dari ibdata1 ). ANDA TIDAK BISA HANYA SIMPLY HAPUS ibdata1DENGAN TITIK INI !!! Harap dicatat bahwa ibdata1tidak menyusut sama sekali.

Pembersihan Infrastruktur InnoDB

Untuk menyusut ibdata1sekali dan untuk semua Anda harus melakukan hal berikut:

  1. Buang (misalnya, dengan mysqldump) semua basis data ke dalam .sqlfile teks ( SQLData.sqldigunakan di bawah)

  2. Jatuhkan semua basis data (kecuali untuk mysqldan information_schema) CAVEAT : Sebagai tindakan pencegahan, jalankan skrip ini untuk memastikan Anda memiliki semua hibah pengguna:

    mkdir /var/lib/mysql_grants
    cp /var/lib/mysql/mysql/* /var/lib/mysql_grants/.
    chown -R mysql:mysql /var/lib/mysql_grants
  3. Login ke mysql dan jalankan SET GLOBAL innodb_fast_shutdown = 0;(Ini akan sepenuhnya menghapus semua perubahan transaksi yang tersisa dari ib_logfile0dan ib_logfile1)

  4. Shutdown MySQL

  5. Tambahkan baris berikut ke /etc/my.cnf(atau my.inidi Windows)

    [mysqld]
    innodb_file_per_table
    innodb_flush_method=O_DIRECT
    innodb_log_file_size=1G
    innodb_buffer_pool_size=4G

    (Sidenote: Apa pun yang Anda setel untuk innodb_buffer_pool_size, pastikan innodb_log_file_size25% dari innodb_buffer_pool_size.

    Juga: innodb_flush_method=O_DIRECTtidak tersedia di Windows)

  6. Hapus ibdata*dan ib_logfile*, Secara opsional, Anda dapat menghapus semua folder /var/lib/mysql, kecuali /var/lib/mysql/mysql.

  7. Mulai MySQL (Ini akan membuat ulang ibdata1[10MB secara default] dan ib_logfile0dan ib_logfile1pada 1G masing-masing).

  8. Impor SQLData.sql

Sekarang, ibdata1masih akan tumbuh tetapi hanya berisi tabel metadata karena setiap tabel InnoDB akan ada di luar ibdata1. ibdata1tidak akan lagi berisi data InnoDB dan indeks untuk tabel lainnya.

Misalnya, anggap Anda memiliki tabel InnoDB bernama mydb.mytable. Jika Anda melihat /var/lib/mysql/mydb, Anda akan melihat dua file yang mewakili tabel:

  • mytable.frm (Header Mesin Penyimpan)
  • mytable.ibd (Tabel Data dan Indeks)

Dengan innodb_file_per_tableopsi di /etc/my.cnf, Anda dapat menjalankan OPTIMIZE TABLE mydb.mytabledan file /var/lib/mysql/mydb/mytable.ibdakan benar-benar menyusut.

Saya telah melakukan ini berkali-kali dalam karir saya sebagai DBA MySQL. Faktanya, pertama kali saya melakukan ini, saya menyusutkan file 50GB ibdata1 menjadi hanya 500MB!

Cobalah. Jika Anda memiliki pertanyaan lebih lanjut tentang ini, tanyakan saja. Percayalah kepadaku; ini akan bekerja dalam jangka pendek maupun jangka panjang.

CAVEAT

Pada Langkah 6, jika mysql tidak dapat memulai kembali karena mysqlskema mulai dijatuhkan, lihat kembali pada Langkah 2. Anda membuat salinan fisik mysqlskema. Anda dapat mengembalikannya sebagai berikut:

mkdir /var/lib/mysql/mysql
cp /var/lib/mysql_grants/* /var/lib/mysql/mysql
chown -R mysql:mysql /var/lib/mysql/mysql

Kembali ke Langkah 6 dan lanjutkan

UPDATE 2013-06-04 11:13 EDT

Berkenaan dengan pengaturan innodb_log_file_size ke 25% dari innodb_buffer_pool_size pada Langkah 5, aturan blanket itu agak kuno.

Kembali July 03, 2006, Percona punya artikel bagus mengapa memilih innodb_log_file_size yang tepat . Kemudian, pada Nov 21, 2008, Percona menindaklanjuti dengan artikel lain tentang bagaimana cara menghitung ukuran yang tepat berdasarkan beban kerja puncak menjaga satu jam perubahan .

Sejak itu saya telah menulis posting di DBA StackExchange tentang menghitung ukuran log dan di mana saya mereferensikan dua artikel Percona itu.

Secara pribadi, saya masih akan pergi dengan aturan 25% untuk pengaturan awal. Kemudian, karena beban kerja dapat lebih akurat ditentukan dari waktu ke waktu dalam produksi, Anda dapat mengubah ukuran log selama siklus pemeliharaan hanya dalam hitungan menit.

RolandoMySQLDBA
sumber
9
Saya juga telah menggunakan opsi innodb_file_per_table untuk efek yang besar, memiliki 200 database dengan masing-masing 200 tabel pada satu server, saya dapat menyatukan perbedaan database ke partisi yang berbeda, oleh karena itu menggunakan lebih banyak buffer IO dan spindle yang seharusnya tersedia :)
Dave Rix
2
@SeanDowney BTW ingatlah untuk menaikkan innodb_open_tablesjika perlu. Standarnya adalah 300.
RolandoMySQLDBA
2
@ giorgio79 Anda perlu mengatur penyisipan massal Anda ke nilai yang lebih besar. Ini poin yang bagus. Saya akan menambahkan inti pertanyaan Anda pada jawaban saya.
RolandoMySQLDBA
3
Dalam sistem 32 bit, nilai 4Gb untuk innodb_buffer_pool_size tidak diizinkan. Mysql akan mulai secara diam-diam dengan innodb dinonaktifkan dan tabel yang dipulihkan akan diubah ke myisam. Gunakan nilai yang sedikit lebih kecil untuk memperbaikinya.
David
5
Tuhan yang baik Saya hanya ingin mengatakan ini mungkin salah satu jawaban terbaik yang pernah saya lihat di pekerjaan SANGAT BAIK, Pak. Membantu saya menemukan solusi untuk masalah saya ketika saya mendapatkan ERROR 2013 (HY000) saat mengimpor 154g db. Terima kasih atas jawaban yang bagus!
Josh Brown
4

Mesin InnoDB tidak menyimpan data yang dihapus. Saat Anda menyisipkan dan menghapus baris, ruang yang tidak digunakan dibiarkan dialokasikan dalam file penyimpanan InnoDB. Seiring waktu, ruang keseluruhan tidak akan berkurang, tetapi seiring waktu ruang 'dihapus dan dibebaskan' akan secara otomatis digunakan kembali oleh server DB.

Anda dapat lebih lanjut menyetel dan mengelola ruang yang digunakan oleh mesin melalui re-org manual dari tabel. Untuk melakukan ini, dump data di tabel yang terkena menggunakan mysqldump, letakkan tabel, restart layanan mysql, dan kemudian buat kembali tabel dari file dump.

bigjeff
sumber