Bagaimana Anda menghapus fragmentasi dari tabel InnoDB?

13

Saya memiliki Database yang memiliki sejumlah tabel.

Saya ingin menghapus beberapa catatan dari tabel mengatakan tidak ada catatan lebih dari 20 ribu atau 50 ribu.

Semua Tabel adalah InnoDB. Dan file_per_tableadalah off .

Ketika saya akan menghapus catatan dari sejumlah tabel akan ada fragmentasi dalam tabel.

Apakah ada cara untuk menghapus fragmentasi.?

Pembaruan Pada 17 April

mysql> select TABLE_NAME, TABLE_SCHEMA, Data_free from information_schema.TABLES where TABLE_SCHEMA NOT IN ('information_schema', 'mysql') and Data_Free >0;
+-----------------+--------------+-----------+
| TABLE_NAME      | TABLE_SCHEMA | Data_free |
+-----------------+--------------+-----------+
| City            | world_innodb |   5242880 |
| City_Copy       | world_innodb |   5242880 |
| Country         | world_innodb |   5242880 |
| CountryLanguage | world_innodb |   5242880 |
| a               | world_innodb |   5242880 |
| t1              | world_innodb |   5242880 |
| t2              | world_innodb |   5242880 |
+-----------------+--------------+-----------+
7 rows in set (0.00 sec)

Jadi Sekarang Pertanyaan saya adalah bagaimana saya akan memutuskan bahwa tabel saya terfragmentasi atau tidak.

Abdul Manaf
sumber
1
Dan sebuah artikel InnoDB: menjaga fragmentasi dari situs blog Percona.
ypercubeᵀᴹ

Jawaban:

14

Saya telah membahas ini di StackOverflow pada Oktober 2010 .

Ingatlah file tersibuk di infrastruktur InnoDB: / var / lib / mysql / ibdata1

File ini biasanya menampung empat jenis informasi

  • Tabel Data
  • Indeks Tabel
  • Data MVCC (Multiversioning Concurrency Control)
  • Table Metadata (Daftar ID tablespace)

Berlari OPTIMIZE TABLEmelawan tabel InnoDB yang disimpan di ibdata1 melakukan dua hal:

  • Membuat data tabel dan indeks berdekatan di dalam ibdata1, sehingga lebih cepat diakses
  • Itu membuat ibdata1 tumbuh karena data yang berdekatan dan halaman indeks ditambahkan ke ibdata1

Meskipun Anda dapat memisahkan Data Tabel dan Indeks Tabel dari ibdata1 dan mengelolanya secara independen menggunakan innodb_file_per_table , seluruh ruang disk yang besar di ibdata1 tidak akan hilang dan tidak dapat direklamasi. Anda harus berbuat lebih banyak.

Untuk menyusutkan ibdata1 sekali dan untuk semua Anda harus melakukan hal berikut:

1) MySQLDump semua database menjadi file teks SQL (sebut saja /root/SQLData.sql)

2) Jatuhkan semua basis data (kecuali skema mysql)

3) Matikan mysql

4) Tambahkan baris berikut ke /etc/my.cnf

[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 atur untuk innodb_buffer_pool_size, pastikan innodb_log_file_size adalah 25% dari innodb_buffer_pool_size.

5) Hapus ibdata1, ib_logfile0 dan ib_logfile1

Pada titik ini, seharusnya hanya ada skema mysql di / var / lib / mysql

6) Mulai ulang mysql

Ini akan membuat ulang data ib di 10 atau 18MB (tergantung pada versi MySQL), ib_logfile0 dan ib_logfile1 masing-masing 1G

7) Muat ulang /root/SQLData.sql ke mysql

ibdata1 akan tumbuh tetapi hanya berisi tabel metadata. Bahkan, itu akan tumbuh sangat lambat selama bertahun-tahun. Satu-satunya cara pertumbuhan ibdata1 dengan cepat adalah jika Anda memiliki satu atau lebih hal berikut ini:

  • Banyak DDL ( CREATE TABLE, DROP TABLE, ALTER TABLE)
  • Banyak transaksi
  • Banyak perubahan untuk dilakukan per transaksi

Setiap tabel InnoDB akan ada di luar ibdata1

Misalkan Anda memiliki tabel InnoDB bernama mydb.mytable. Jika Anda masuk ke / var / lib / mysql / mydb, Anda akan melihat dua file yang mewakili tabel

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

ibdata1 tidak akan pernah lagi memuat data dan Indeks InnoDB.

Dengan opsi innodb_file_per_table di /etc/my.cnf, Anda dapat menjalankan OPTIMIZE TABLE mydb.mytable;dan file /var/lib/mysql/mydb/mytable.ibd akan menyusut.

Saya telah melakukan ini berkali-kali dalam karir saya sebagai DBA MySQL

Faktanya, pertama kali saya melakukan ini, saya menciutkan file ibdata1 50GB menjadi 500MB.

Cobalah. Jika Anda memiliki pertanyaan lebih lanjut tentang ini, email saya. Percayalah kepadaku. Ini akan bekerja dalam jangka pendek dan jangka panjang !!!

UPDATE 2012-04-19 09:23 EDT

Setelah menjalankan langkah-langkah di atas, bagaimana Anda bisa menentukan tabel apa yang perlu didefragmentasi? Dimungkinkan untuk mengetahuinya, tetapi Anda akan memiliki skripnya.

Berikut ini sebuah contoh: Misalkan Anda memiliki tabel mydb.mytable. Dengan diaktifkan innodb_file_per_table, Anda memiliki file /var/lib/mysql/mydb/mytable.ibd

Anda harus mengambil dua angka

MEMASANG DARI OS: Anda dapat memastikan ukuran file dari OS seperti ini

ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'

FILESIZE DARI INFORMATION_SCHEMA: Anda dapat memastikan filesize dari information_schema.tabel seperti ini:

SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';

Cukup kurangi nilai INFORMATION_SCHEMA dari nilai OS dan bagilah selisihnya dengan nilai INFORMATION_SCHEMA.

Dari sana Anda akan memutuskan berapa persen yang dianggap perlu untuk men-defrag tabel itu. Tentu saja, Anda defrag menggunakan salah satu dari perintah berikut:

OPTIMIZE TABLE mydb.mytable;

atau

ALTER TABLE mydb.mytable ENGINE=InnoDB;
RolandoMySQLDBA
sumber
saya tidak berpikir / var / lib / mysql / ibdata1 sangat sibuk jika Anda menggunakan innodb_file_per_table = opsi 1 yang direkomendasikan
CrackerJack9
1
@ CrackerJack9 ibdata1 sangat luar biasa karena apa yang masuk ke dalamnya: 1) Info buffer tulis ganda, 2) Masukkan Buffer untuk Indeks Sekunder, 3) Kamus data, 4) Rollback Segments, 5) Undo Tablespace. Silakan goto scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing untuk representasi gambar hal-hal ini. Bahkan dengan penghapusan data dan halaman indeks untuk tabel InnoDB, ibdata1 masih dapat tumbuh secara signifikan dalam lingkungan transaksional yang tinggi.
RolandoMySQLDBA
1
@ CrackerJack9 Saya punya posting tambahan yang membahas kegiatan tambahan di sekitar ibdata1: dba.stackexchange.com/a/23367/877
RolandoMySQLDBA
Saya tidak menyadari bahwa itu masih sangat banyak digunakan. Sangat dihargai!
CrackerJack9
@RolandoMySQLDBA Bisakah Anda muncul di Heap ketika Anda punya waktu?
ypercubeᵀᴹ
5

Jika Anda sering menghapus baris (atau memperbarui baris dengan tipe data panjang variabel), Anda bisa berakhir dengan banyak ruang kosong di file data Anda, mirip dengan fragmentasi sistem file.

Jika Anda tidak menggunakan innodb_file_per_tableopsi, satu-satunya hal yang dapat Anda lakukan adalah mengekspor dan mengimpor basis data, prosedur intensif-waktu dan disk.

Tetapi jika Anda menggunakan innodb_file_per_table, Anda dapat mengidentifikasi dan mendapatkan kembali ruang ini!

Sebelum 5.1.21, penghitung ruang kosong tersedia dari kolom table_comment dari information_schema.tables. Berikut adalah beberapa SQL untuk mengidentifikasi tabel dengan setidaknya 100M (sebenarnya 97.65M) ruang kosong:

SELECT table_schema, table_name, table_comment DARI
information_schema.tables DI MANA MESIN SEPERTI 'InnoDB' DAN table_comment RLIKE 'InnoDB gratis: ([0-9] {6,}). *';

Dimulai dengan 5.1.21, ini dipindahkan ke kolom data_free (tempat yang jauh lebih tepat):

SELECT table_schema, table_name, data_free / 1024/1024 SEBAGAI data_free_MB DARI information_schema.tables MANA MESIN SEPERTI 'InnoDB' DAN data_free> 100 * 1024 * 1024;

Anda bisa mendapatkan kembali ruang yang hilang dengan membangun kembali tabel. Cara terbaik untuk melakukan ini adalah menggunakan 'alter table' tanpa benar-benar mengubah apa pun:

ALTER TABLE `TableName` ENGINE=InnoDB;

Inilah yang dilakukan MySQL di balik layar jika Anda menjalankan 'optimalkan tabel' pada tabel InnoDB. Ini akan menghasilkan kunci baca, tetapi bukan kunci tabel penuh. Berapa lama waktu yang dibutuhkan sepenuhnya tergantung pada jumlah data dalam tabel (tetapi tidak pada ukuran file data). Jika Anda memiliki tabel dengan banyak penghapusan atau pembaruan, Anda mungkin ingin menjalankan ini setiap bulan, atau bahkan setiap minggu.

Mahesh Patil
sumber
Satu hal lagi saya tidak dapat mengerti apa arti data_free> 100 * 1024 * 1024 ..? Dan ketika saya melihat hasilnya saya tidak dapat memutuskan bahwa tabel tersebut terfragmentasi atau tidak .. ?? Apakah ada cara sehingga saya dapat mengatakan tabel terfragmentasi atau tidak terfragmentasi.?
Abdul Manaf
lihat bagian pembaruan saya.
Abdul Manaf