Pemeliharaan indeks MySQL

12

Saya membuat banyak penelitian tentang cara mempertahankan indeks di MySQL untuk mencegah fragmentasi dan untuk mengoptimalkan entah bagaimana pelaksanaan beberapa pertanyaan.

Saya kenal dengan rumus yang menghitung rasio antara ruang maks yang tersedia untuk tabel VS ruang yang digunakan oleh data dan indeks.

Namun pertanyaan utama saya masih belum terjawab. Mungkin ini disebabkan oleh fakta bahwa saya terbiasa dengan pemeliharaan indeks di SQL Server, dan saya cenderung berpikir bahwa di MySQL itu harus serupa.

Di SQL server, Anda dapat memiliki beberapa indeks, dan masing-masingnya dapat memiliki tingkat fragmentasi yang berbeda. Kemudian Anda dapat mengambil satu dan melakukan operasi 'REORGANIZE' atau 'REBUILD' dalam indeks tertentu, tanpa mempengaruhi sisanya.

Sepengetahuan saya, tidak ada 'tabel fragmentasi' seperti itu, dan SQL Server tidak menyediakan alat untuk memperbaiki 'tabel fragmentasi'. Apa yang disediakannya adalah alat untuk memeriksa fragmentasi indeks (dipahami seperti rasio antara jumlah halaman yang digunakan oleh indeks VS kepenuhan halaman itu dan kedekatan), serta fragmentasi internal dan eksternal.

Semua itu cukup mudah dimengerti, setidaknya bagi saya.

Sekarang, ketika tiba giliran untuk mempertahankan indeks di MySQL, hanya ada konsep fragmentasi tabel, seperti yang disebutkan di atas.

Sebuah tabel di MySQL dapat memiliki beberapa indeks, tetapi ketika saya memeriksa 'rasio fragmentasi' dengan rumus terkenal itu, saya tidak melihat fragmentasi dari setiap indeks, tetapi tabel secara keseluruhan.

Ketika saya ingin mengoptimalkan indeks di MySQL, saya tidak memilih indeks tertentu untuk beroperasi (seperti dalam SQL Server). Sebagai gantinya, saya melakukan operasi 'MENGOPTIMALKAN' di seluruh tabel, yang mungkin mempengaruhi semua indeks.

Ketika tabel dioptimalkan dalam MySQL, rasio antara ruang yang digunakan oleh data + indeks VS ruang keseluruhan berkurang, yang menyarankan beberapa jenis pengorganisasian ulang fisik dalam hard drive, yang diterjemahkan menjadi pengurangan ruang fisik. Namun, indeks fragmentasi tidak hanya tentang ruang fisik, tetapi struktur pohon yang telah berubah seiring waktu karena sisipan dan pembaruan.

Akhirnya, saya mendapat meja di InnoDB / MySQL. Tabel itu memiliki 3 juta catatan, 105 kolom, dan 55 indeks. Ini adalah 1.5GB tidak termasuk indeks, yang 2.1GB.

Tabel itu dipukul ribuan kali setiap hari untuk memperbarui, penyisipan (kami tidak benar-benar menghapus catatan).

Tabel itu telah dibuat bertahun-tahun dan saya tahu pasti tidak ada yang mempertahankan indeks apa pun.

Saya mengharapkan untuk menemukan fragmentasi besar di sana, tetapi ketika saya melakukan perhitungan fragmentasi seperti yang ditentukan

free_space / (data_length + index_length)

ternyata saya hanya memiliki 0,2% fragmentasi. IMHO itu cukup tidak realistis.

Jadi pertanyaan besarnya adalah:

  1. Bagaimana cara memeriksa fragmentasi indeks tertentu di MySQL, bukan tabel secara keseluruhan
  2. Apakah OPTIMIZE TABLE benar-benar memperbaiki fragmentasi internal / eksternal indeks seperti pada SQL Server?
  3. Ketika saya mengoptimalkan tabel di MySQL, apakah itu benar-benar membangun kembali semua indeks di atas meja?
  4. Apakah realistis untuk berpikir bahwa mengurangi ruang fisik indeks (tanpa membangun kembali pohon itu sendiri) benar-benar diterjemahkan menjadi kinerja yang lebih baik?
Nicolas
sumber
mengoptimalkan tabel tentu saja membersihkan indeks berkerumun di innodb
1
ini adalah pertanyaan yang bagus, hanya saja bukan pemrograman. Akan dipindahkan ke tempatnya:>

Jawaban:

6

Indeks fragmentasi terlalu berlebihan. Jangan khawatir tentang hal itu.

Dua blok yang berdekatan, agak kosong, digabung bersama oleh InnoDB sebagai pemrosesan alami.

Tindakan acak pada BTree menyebabkannya tertarik secara alami ke rata-rata 69% penuh. Tentu, ini bukan 100%, tetapi biaya overhead "memperbaiki" tidak sepadan.

SHOW TABLE STATUS memberi Anda beberapa metrik, tetapi cacat - "Data_free" mencakup ruang "bebas" tertentu, tetapi bukan ruang "bebas" lainnya.

Ada ruang yang tidak digunakan di setiap blok; blok 16KB gratis; "luasan" gratis (potongan nMB); Baris MVCC menunggu untuk dituai; node non-daun memiliki fragmentasi sendiri; dll.

Percona dan Oracle memiliki cara berbeda dalam melihat seberapa besar (jumlah blok) indeks. Saya menemukan keduanya tidak berguna karena definisi terbatas "bebas". Tampaknya blok (masing-masing 16KB) dialokasikan dalam potongan (beberapa MB), sehingga membuat orang percaya bahwa ada segala macam fragmentasi. Pada kenyataannya, biasanya hanya sebagian besar dari potongan multi-MB ini. Dan OPTIMIZE TABLEtidak perlu menutup ruang.

Jika SQL Server menggunakan BTrees, maka berbohong untuk mengatakan bahwa "tidak ada fragmentasi". Pikirkan apa yang terjadi pada "block split". Atau pikirkan overhead defragmenting yang terus menerus. Bagaimanapun Anda kalah.

Perhatikan lebih lanjut bahwa tabel dan indeks pada dasarnya adalah struktur yang identik:

  • B + Tree, berdasarkan pada beberapa indeks
  • "Data" didasarkan pada KUNCI UTAMA; setiap indeks sekunder adalah B + Tree berdasarkan indeksnya.
  • Node daun "data" berisi semua kolom tabel.
  • Node daun indeks sekunder berisi kolom indeks sekunder itu, ditambah kolom KUNCI UTAMA.

Jika sudah innodb_file_per_table = ON, Anda dapat dengan jelas melihat penyusutan (jika ada) setelah OPTIMASI TABEL dengan melihat .ibdukuran file. Sebab OFF, info dimakamkan ibdata1, tetapi SHOW TABLE STATUSmungkin cukup akurat karena semua "bebas" ruang milik setiap tabel. Nah, kecuali untuk potongan yang dialokasikan sebelumnya.

Anda mungkin memperhatikan bahwa tabel file-per-tabel yang baru dioptimalkan memiliki tepat 4M, 5M, 6M, atau 7M dari Data_free. Sekali lagi, ini adalah pra-alokasi, dan kegagalan untuk memberi Anda detail menit.

Saya telah bekerja dengan InnoDB selama lebih dari satu dekade; Saya telah bekerja dengan ribuan meja yang berbeda, besar dan kecil. Saya katakan bahwa hanya satu meja dalam seribu yang benar-benar dibutuhkan OPTIMIZE TABLE. Menggunakannya di meja lain adalah pemborosan.

105 kolom banyak, tapi mungkin tidak terlalu banyak.

Apakah Anda memiliki 55 indeks pada satu tabel? Itu buruk. Itu adalah 55 pembaruan per INSERT. Mari kita bahas lebih lanjut. Ingatlah bahwa INDEX(a)itu tidak berguna jika Anda juga memilikinya INDEX(a,b). Dan INDEX(flag)tidak berguna karena kardinalitas rendah. (Tapi INDEX(flag, foo)semoga bermanfaat.)

T1: Tidak ada cara yang baik untuk memeriksa semua bentuk fragmentasi baik dalam data atau indeks sekunder.

Q2, Q3: OPTIMIZE TABLEmembangun kembali tabel dengan CREATEingtabel baru dan INSERTingsemua baris, lalu RENAMEingdan DROPping. Memasukkan kembali data dalam urutan PK memastikan bahwa data didefragmentasi dengan baik. Indeks adalah masalah lain.

T4: Anda dapat DROP dan reCREATEsetiap indeks untuk membersihkannya. Tetapi ini adalah proses yang sangat lambat. 5.6 memiliki beberapa speedup, tetapi saya tidak tahu apakah mereka membantu defragmentasi.

Hal ini juga memungkinkan untuk ALTER TABLE ... DISABLE KEYS, kemudian ENABLEmereka. Ini mungkin untuk membangun kembali semua indeks sekunder secara lebih efisien sekaligus.

Rick James
sumber
Rick, maksudku bidang '105', bukan file
Nicolas
1

Bagaimana cara memeriksa fragmentasi indeks tertentu di MySQL, bukan tabel secara keseluruhan

Lulus.

Apakah OPTIMIZE TABLE benar-benar memperbaiki fragmentasi internal / eksternal indeks seperti pada SQL Server?

Itu benar-benar membangun kembali tabel dan indeksnya.

Ketika saya mengoptimalkan tabel di MySQL, apakah itu benar-benar membangun kembali semua indeks di atas meja?

Itu pertanyaan yang sama dengan jawaban yang sama.

Apakah realistis untuk berpikir bahwa mengurangi ruang fisik indeks (tanpa membangun kembali pohon itu sendiri) benar-benar diterjemahkan menjadi kinerja yang lebih baik?

Tidak realistis untuk berpikir Anda dapat mengurangi ruang tanpa membangun kembali pohon. Mereka pergi bersama.

pengguna207421
sumber
Untuk menjawab # 1: Meskipun tidak terlalu akurat, tetapi SHOW TABLE STATUS LIKE 'mytable'akan memberikan petunjuk di data freekolom. dev.mysql.com/doc/refman/5.6/id/show-table-status.html
Jehad Keriaki
Saya tahu, tetapi masih ada ruang indeks tertentu
Nicolas