Bagaimana menemukan dan memperbaiki tabel MySQL yang terfragmentasi

27

Saya menggunakan MySQLTuner yang menunjukkan beberapa tabel terfragmentasi. Saya menggunakan

mysqlcheck --optimize -A

untuk mengoptimalkan semua tabel. Itu memperbaiki beberapa tabel tetapi MySQLTuner masih menemukan 19 tabel terfragmentasi. bagaimana saya bisa melihat tabel mana yang membutuhkan defragmenting? Mungkin TABEL MENGOPTIMAL akan bekerja di mana mysqlcheck tidak? Atau apa lagi yang harus saya coba?

penasaran kucing
sumber
1
Saya punya masalah serupa. Saya menyiapkan DB baru dengan MySQL 5.5 dan tabel InnoDB tertentu tidak pernah dihapus. Saya bertanya-tanya apakah pemeriksaan Data_free (ditunjukkan dalam jawaban KayakJim) salah dengan tabel InnoDB.
docwhat

Jawaban:

38

jawaban singkatnya:

select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

Jawaban "Kamu harus tahu"

pertama-tama Anda harus memahami bahwa tabel Mysql terfragmentasi ketika baris diperbarui, jadi ini adalah situasi yang normal. Ketika sebuah tabel dibuat, katakanlah diimpor menggunakan dump dengan data, semua baris disimpan tanpa fragmentasi di banyak halaman ukuran tetap. Saat Anda memperbarui baris panjang variabel, halaman yang berisi baris ini dibagi menjadi dua atau lebih halaman untuk menyimpan perubahan, dan dua halaman baru ini (atau lebih) berisi ruang kosong yang mengisi ruang yang tidak digunakan.

Ini tidak memengaruhi kinerja, kecuali tentu saja fragmentasi tumbuh terlalu banyak. Apa yang terlalu banyak fragmentasi, mari kita lihat permintaan yang Anda cari:

  select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

DATA_LENGTH dan INDEX_LENGTH adalah ruang yang digunakan oleh data dan indeks Anda, dan DATA_FREE adalah jumlah total byte yang tidak digunakan di semua halaman tabel (fragmentasi).

Berikut adalah contoh tabel produksi nyata

| ENGINE | TABLE_NAME               | data_length | index_length | data_free |
| InnoDB | comments                 |         896 |          316 |         5 |

Dalam hal ini kami memiliki Tabel menggunakan (896 + 316) = 1212 MB, dan memiliki data ruang kosong 5 MB. Ini berarti "rasio fragmentasi" dari:

5/1212 = 0.0041

... Yang merupakan "rasio fragmentasi" yang sangat rendah.

Saya telah bekerja dengan tabel dengan rasio mendekati 0,2 (artinya 20% ruang kosong) dan tidak pernah melihat perlambatan pada kueri, bahkan jika saya mengoptimalkan tabel, kinerjanya sama. Tetapi menerapkan tabel optimisasi pada tabel 800MB membutuhkan banyak waktu dan memblokir tabel selama beberapa menit, yang tidak praktis untuk produksi.

Jadi, jika Anda mempertimbangkan apa yang Anda menangkan dalam kinerja dan waktu yang terbuang untuk mengoptimalkan tabel, saya lebih suka TIDAK MENGOPTIMALKAN.

Jika menurut Anda lebih baik untuk penyimpanan, lihat rasio Anda dan lihat berapa banyak ruang yang dapat Anda hemat saat mengoptimalkan. Biasanya tidak terlalu banyak, jadi saya lebih suka TIDAK MENGOPTIMALKAN.

Dan jika Anda mengoptimalkan, pembaruan berikutnya akan membuat ruang kosong dengan membagi halaman menjadi dua atau lebih. Tapi itu lebih cepat untuk memperbarui tabel terfragmentasi daripada yang tidak terfragmentasi, karena jika tabel terfragmentasi, pembaruan pada baris tidak selalu akan membagi halaman.

Saya harap ini membantu Anda.

Felipe Rojas
sumber
1
Meskipun ini adalah jawaban dari beberapa tahun yang lalu, saya pikir saya akan menunjukkan bahwa data_free adalah stat untuk seluruh tablespace, bukan untuk tabel masing-masing. Jika Anda menyimpan beberapa tabel bersama dalam satu tablespace, data_free dapat menyesatkan Anda untuk meyakini bahwa tabel tersebut perlu didefragmentasi, padahal itu hanya berarti ada luasan gratis di tablespace. Menjalankan tabel optimisasi tidak akan mengurangi luasan gratis. Mendefragmentasi tabel bahkan dapat meningkatkan luasan gratis.
Bill Karwin
14

Untuk menambahkan jawaban dari Felipe-Rojas Anda dapat menghitung rasio fragmen sebagai bagian dari permintaan:

select ENGINE,
  concat(TABLE_SCHEMA, '.', TABLE_NAME) as table_name,
  round(DATA_LENGTH/1024/1024, 2) as data_length,
  round(INDEX_LENGTH/1024/1024, 2) as index_length,
  round(DATA_FREE/1024/1024, 2) as data_free,
  (data_free/(index_length+data_length)) as frag_ratio
FROM information_schema.tables
WHERE DATA_FREE > 0
ORDER BY frag_ratio DESC;

Jika sebuah tabel terfragmentasi dalam persentase kecil (kurang dari 5%?) Maka Anda mungkin dapat membiarkannya sendiri.

Apa pun yang lebih besar dan Anda harus menilai berdasarkan penggunaan db Anda, mengunci tabel dll tentang seberapa penting defragment tabel.

sysadmiral
sumber
2

Optimize Table memang akan menyelesaikan masalah yang Anda alami.

Jika Anda hanya memiliki beberapa basis data, maka Anda bisa menggunakan PHPMyAdmin untuk menelusuri semua basis data Anda. Pilih tabel dengan overhead dan kemudian pilih untuk mengoptimalkan.

Jika Anda memiliki banyak basis data, maka metode lain mungkin lebih disukai.

Saya menggunakan pengaturan skrip PHP berikut di cron untuk dijalankan setiap jam.

$DB = new mysqli ('localhost', 'DbUser', 'DbPassword');
$results = $DB->query('show databases');
$allDbs = array();
while ($row = $results->fetch_array(MYSQLI_NUM))
{
    $allDbs[] = $row[0];
}
$results->close();
foreach ($allDbs as $dbName)
{
    if ($dbName != 'information_schema' && $dbName != 'mysql')
    {
        $DB->select_db($dbName);
        $results = $DB->query('SHOW TABLE STATUS WHERE Data_free > 0');
        if ($results->num_rows > 0)
        {
            while ($row = $results->fetch_assoc())
            {
                $DB->query('optimize table ' . $row['Name']);
            }
        }
        $results->close();
    }
}
$DB->close();
Daemon of Chaos
sumber
3
Saya cukup yakin itu mysqlcheck --optimize -Asama dengan SQLOPTIMIZE TABLE <tablename>;
docwhat
2

Saya menemukan halaman ini dan menemukan pertanyaan oleh Felipe-Rojas dan sysadmiral sangat membantu. Tetapi dalam kasus saya, saya menjalankan kueri dalam phpMyAdmin WHM dan hanya mendapatkan TABLE_NAME tidak membantu karena database tidak terdaftar, dan beberapa database memiliki nama tabel yang sama. Jadi, menambahkan saja TABLE_SCHEMAakan memberikan kolom itu juga.

select  ENGINE, TABLE_SCHEMA, TABLE_NAME, Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free, (data_free/(index_length+data_length)) as frag_ratio from information_schema.tables  where  DATA_FREE > 0 order by frag_ratio desc

Menunjukkan DB

ENGINE  | TABLE_SCHEMA  | TABLE_NAME    | data_length   | index_length  | data_free | frag_ratio

InnoDB  | db_name       | db_table      | 0             | 0             | 8         | 170.6667

Untuk "memperbaiki" saya menggunakan tautan tabel Defragment di phpMyAdmin untuk masing-masing tabel yang menghasilkan "frag_ratio" yang tinggi yang dieksekusi oleh phpMyAdmin:

ALTER TABLE `table_name` ENGINE = InnoDB;
Chris
sumber
0

Sebuah tabel menggunakan Mesin InnoDB MySQL pada dasarnya tidak perlu OPTIMIZEd.

Nilai Data_freedari salah satu information_schema.tablesatau SHOW TABLE STATUSsangat sering bukan nol, bahkan ketika Anda berpikir telah melakukan semua yang dapat Anda lakukan defrag tabel Anda. Lebih jauh, metrik itu hanyalah satu dari beberapa fragmentasi yang dapat dan memang terjadi. (Juga, membuang ruang dalam blok, membatalkan daftar, indeks BTrees vs data BTrees, dll, dll.

Dan innodb_file_per_tablemempersulit penggunaan Data_free. Jika tabel di ibdata1, maka Data_freemerujuk ke seluruh tablespace; nomor yang agak tidak berguna. Jika tabel di .ibdfile sendiri , kemungkinan beberapa MB atau beberapa persen dari ukuran tabel, mana yang lebih besar.

Hanya jika Anda telah menghapus banyak baris dan tidak berniat untuk mengisi ulang tabel, mungkin itu layak dijalankan OPTIMIZE TABLE.

PARTITIONsjuga menunjukkan jumlah yang mengganggu Data_free, karena setiap partisi biasanya menunjukkan 4-7MB "bebas". Dan ini tidak akan hilang.

Mengapa Mendefragmentasi?

  • Untuk mengembalikan ruang ke OS? Nah, Anda mungkin mencapai ini secara singkat jika Anda punya innodb_file_per_table=1. Tetapi saat Anda menambahkan baris, Anda akan mengambilnya kembali dari OS.
  • Untuk mempercepat akses? Lupakan. Tata letak blok pada disk relatif acak, dan telah selama beberapa dekade terakhir. Setengah abad yang lalu, agak penting untuk mengatur ulang blok.
  • Untuk menyeimbangkan kembali BTrees? Begitu? Mereka akan segera menjadi tidak seimbang lagi. Kondisi mapan untuk BTrees yang dimasukkan secara acak ke dalam adalah 69%. Dan itu bahkan tidak diperhitungkan Data_free.
  • MySQLTuner mengatakan kepada? Produk itu perlu dingin.

Catatan sejarah. Ketika saya sedang membantu DBA dengan sebagian besar tabel MyISAM, saya menemukan mungkin 2 dari 1000 tabel yang dibantu oleh bulanan OPTIMIZE . Sejak itu, saya telah bekerja dengan ribuan tabel InnoDB, belum menemukan masalah kinerja yang mungkin bisa ditolong OPTIMIZE. (Tentu, ada masalah ruang disk yang OPTIMIZEmungkin bisa membantu, tetapi itu menjadi rumit - biasanya DBA tidak memiliki cukup ruang disk untuk dijalankan OPTIMIZE!)

Rick James
sumber