Ketika melihat permintaan yang sangat mengganggu atas tabel MyISAM yang membutuhkan waktu lama untuk dieksekusi pada beberapa kesempatan, saya telah mencatat bahwa MySQL tampaknya mengekspos pola I / O yang agak aneh: ketika mengeksekusi permintaan tunggal dan harus melakukan signifikan jumlah I / O (misalnya untuk pemindaian tabel atau ketika cache kosong sebagai akibatnya echo 3 > /proc/sys/vm/drop_caches
sehingga indeks harus dimuat dari disk terlebih dahulu), ukuran antrian untuk perangkat blok yang mendasarinya mendekati nilai 1, dengan kinerja luar biasa dari hanya 4-5 MB / s:
root@mysql-test:~# iostat -xdm 5 /dev/sda
Linux 3.2.0-40-generic (mysql-test) 04/30/2014 _x86_64_ (4 CPU)
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.14 24.82 18.26 88.79 0.75 4.61 102.56 2.83 26.39 19.29 27.85 2.46 26.31
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 69.29 151.52 72.73 5.31 0.59 53.95 1.21 5.39 7.84 0.29 4.39 98.51
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 153.06 144.29 174.69 4.96 1.36 40.54 1.39 4.36 8.91 0.60 3.15 100.49
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 105.75 150.92 109.03 4.53 0.85 42.41 1.29 4.96 8.15 0.54 3.90 101.36
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 48.89 156.36 51.72 5.28 0.76 59.38 1.28 6.16 8.02 0.55 4.77 99.23
Sementara 150 IOPS adalah disk tunggal dalam konfigurasi yang diberikan yang mampu menghasilkan I / O acak, hasilnya masih sangat mengejutkan saya karena saya berharap MySQL dapat menjalankan I / O asinkron untuk membaca dan mengambil sejumlah besar blok secara bersamaan alih-alih membaca dan mengevaluasinya satu per satu, secara efektif mengabaikan perolehan paralelisasi yang tersedia dalam konfigurasi RAID. Apa keputusan desain atau opsi konfigurasi yang bertanggung jawab untuk ini? Apakah ini masalah khusus platform?
Sementara saya telah menguji ini dengan tabel MyISAM besar-ish, saya melihat efek yang sama dengan tabel yang sama dikonversi ke InnoDB (meskipun tidak seburuk itu, permintaan sampel masih membutuhkan waktu 20-30 detik dengan sebagian besar waktu dihabiskan untuk membaca disk dengan panjang antrian 1) setelah saya me-restart daemon mysql dan oleh karena itu kolam buffer kosong. Saya juga telah memverifikasi bahwa masalah yang sama tetap pada 5,6 GA dan saat ini 5,7 tonggak sejarah 14 - selama saya menggunakan utas permintaan tunggal, MySQL tampaknya tidak dapat memparalelkan operasi I / O yang diperlukan untuk pemrosesan permintaan.
Sesuai permintaan beberapa detail tambahan pada skenario. Perilaku dapat diamati dengan banyak jenis kueri. Saya telah secara sewenang-wenang memilih satu untuk pengujian lebih lanjut yang berbunyi seperti ini:
SELECT herp.id, herp.firstname, herp.lastname, derp.label, herp.email,
(SELECT CONCAT(label, " (", zip_code, " ", city,")" ) FROM subsidiaries WHERE subsidiaries.id=herp.subsidiary_id ) AS subsidiary,
(SELECT COUNT(fk_herp) from herp_missing_data WHERE fk_herp=herp.id) AS missing_data
FROM herp LEFT JOIN derp ON derp.id=herp.fk_derp
WHERE (herp.fk_pools='123456') AND herp.city LIKE '%Some City%' AND herp.active='yes'
ORDER BY herp.id desc LIMIT 0,10;
Saya tahu bahwa ia memiliki beberapa ruang untuk optimasi, tetapi saya memutuskan untuk berhenti karena beberapa alasan dan berkonsentrasi pada mencari penjelasan umum untuk pola I / O yang tidak terduga yang saya lihat.
Tabel yang digunakan memang memiliki banyak data di dalamnya:
mysql> select table_name, engine, table_rows, data_length, index_length from information_schema.tables WHERE tables.TABLE_SCHEMA = 'mydb' and tables.table_name in ( 'herp', 'derp', 'missing_data', 'subsidiaries');
+-------------------------+--------+------------+-------------+--------------+
| table_name | engine | table_rows | data_length | index_length |
+-------------------------+--------+------------+-------------+--------------+
| derp | MyISAM | 14085 | 1118676 | 165888 |
| herp | MyISAM | 821747 | 828106512 | 568057856 |
| missing_data | MyISAM | 1220186 | 15862418 | 29238272 |
| subsidiaries | MyISAM | 1499 | 6490308 | 103424 |
+-------------------------+--------+------------+-------------+--------------+
4 rows in set (0.00 sec)
Sekarang ketika saya menjalankan kueri di atas tabel-tabel ini, saya mendapatkan waktu eksekusi lebih dari 1 menit sementara sistem tampaknya terus-menerus sibuk membaca data dari disk dengan satu utas.
Profil untuk eksekusi permintaan sampel (yang mengambil 1 menit 9,17 detik dalam contoh ini) terlihat seperti ini:
mysql> show profile for query 1;
+--------------------------------+-----------+
| Status | Duration |
+--------------------------------+-----------+
| starting | 0.000118 |
| Waiting for query cache lock | 0.000035 |
| init | 0.000033 |
| checking query cache for query | 0.000399 |
| checking permissions | 0.000077 |
| checking permissions | 0.000030 |
| checking permissions | 0.000031 |
| checking permissions | 0.000035 |
| Opening tables | 0.000158 |
| init | 0.000294 |
| System lock | 0.000056 |
| Waiting for query cache lock | 0.000032 |
| System lock | 0.000116 |
| optimizing | 0.000063 |
| statistics | 0.001964 |
| preparing | 0.000104 |
| Sorting result | 0.000033 |
| executing | 0.000030 |
| Sending data | 2.031349 |
| optimizing | 0.000054 |
| statistics | 0.000039 |
| preparing | 0.000024 |
| executing | 0.000013 |
| Sending data | 0.000044 |
| optimizing | 0.000017 |
| statistics | 0.000021 |
| preparing | 0.000019 |
| executing | 0.000013 |
| Sending data | 21.477528 |
| executing | 0.000070 |
| Sending data | 0.000075 |
| executing | 0.000027 |
| Sending data | 45.692623 |
| end | 0.000076 |
| query end | 0.000036 |
| closing tables | 0.000109 |
| freeing items | 0.000067 |
| Waiting for query cache lock | 0.000038 |
| freeing items | 0.000080 |
| Waiting for query cache lock | 0.000044 |
| freeing items | 0.000037 |
| storing result in query cache | 0.000033 |
| logging slow query | 0.000103 |
| cleaning up | 0.000073 |
+--------------------------------+-----------+
44 rows in set, 1 warning (0.00 sec)
sumber
Jawaban:
Pertama izinkan saya mengklarifikasi dengan mengkonfirmasi bahwa MyISAM tidak melakukan I / O asinkron, tetapi InnoDB melakukannya dan akan secara default dari MySQL 5.5. Sebelum 5,5 digunakan "simulasi AIO" dengan menggunakan utas pekerja.
Saya pikir penting juga untuk membedakan antara tiga situasi:
Untuk (1) I / O akan dapat melakukan secara paralel untuk ini. Ada beberapa batasan dengan MyISAM: penguncian tabel dan kunci global yang melindungi
key_buffer
(cache indeks). InnoDB di MySQL 5.5+ benar-benar bersinar di sini.Untuk (2) saat ini tidak didukung. Kasus penggunaan yang baik adalah dengan mempartisi, di mana Anda bisa mencari setiap tabel dipartisi secara paralel.
Untuk (3) InnoDB memiliki linear baca-depan untuk membaca sepenuhnya (kelompok 64 halaman) jika> 56 halaman dibaca (ini dapat dikonfigurasi), tetapi ada ruang untuk peningkatan lebih lanjut. Facebook telah menulis tentang menerapkan logis-readhead di cabang mereka (dengan keuntungan 10x pada tabel tablescan).
sumber
Saya harap
missing_data
bukan MyISAM karena tabel MyISAM yang kosong biasanya memiliki 1024 byte.MYI
. Ukuran byte yang bukan nol diharapkan dari MyISAM. Sebuah byte nol.MYI
terdengar agak menyeramkan bagi saya.Jika Anda menjalankan kueri metadata ini
dan mesin meja itu adalah MyISAM, Anda harus memperbaikinya.
SISI CATATAN: Jika
engine
adalahNULL
, itu pandangan. Jika ini adalah tampilan atau bukan MyISAM, abaikan sisa posting saya dan tambahkan info itu ke pertanyaan. Jika tabelnya adalah MyISAM, baca terus ...Menurut kueri metadata Anda,
missing_data.MYD
sekitar 46 juta.Pertama, jalankan ini
Anda akan mendapatkan deskripsi tabel atau pesan kesalahan yang mengatakan sesuatu seperti
Jika Anda mendapatkan deskripsi tabel dan itu adalah MyISAM, jalankan
Ini akan membuat ulang tabel tanpa fragmentasi dan menghitung statistik indeks segar. Jika tidak berhasil maka coba:
Itu harus membuat ulang halaman indeks untuk MyISAM.
Agar aman (jika menggunakan MySQL 5.6), jalankan ini setelah perbaikan
Pertanyaanmu
Indeks tabel Anda mungkin tidak dimuat ke dalam memori jika Pengoptimal Permintaan MySQL memutuskan untuk tidak menggunakan. Jika klausa WHERE Anda menentukan sejumlah besar baris harus dibaca dari indeks, MySQL Query Optimizer akan melihat bahwa ketika membuat paket EXPLAIN dan memutuskan untuk menggunakan pemindaian tabel penuh sebagai gantinya.
Operasi I / O paralel pada tabel MyISAM tidak dapat dicapai karena tidak dapat dikonfigurasi.
InnoDB dapat disetel untuk meningkatkan kinerja seperti itu.
sumber