Bei der Betrachtung einer besonders ärgerlichen Abfrage über MyISAM-Tabellen, deren Ausführung mehrmals lange dauert, habe ich festgestellt, dass MySQL ein ziemlich seltsames E / A-Muster aufzudecken scheint: Wenn eine einzelne Abfrage ausgeführt wird und eine signifikante Abfrage ausgeführt werden muss E / A-Menge (z. B. für einen Tabellenscan oder wenn die Caches leer sind, echo 3 > /proc/sys/vm/drop_caches
sodass die Indizes zuerst von der Festplatte geladen werden müssen), liegt die Warteschlangengröße für das zugrunde liegende Blockgerät nahe dem Wert 1 mit einer miserablen Leistung von nur 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
Während die 150 IOPS einfach das sind, was eine einzelne Festplatte in der angegebenen Konfiguration in Bezug auf zufällige E / A liefern kann, überrascht mich das Ergebnis immer noch sehr , da ich erwarten würde, dass MySQL asynchrone E / A für Lese- und Abrufvorgänge ausführen kann Eine große Anzahl von Blöcken gleichzeitig, anstatt sie einzeln zu lesen und auszuwerten, wodurch die in RAID-Konfigurationen verfügbaren Parallelisierungsgewinne effektiv vernachlässigt werden. Welche Entwurfsentscheidung oder Konfigurationsoption ist dafür verantwortlich? Ist das ein plattformspezifisches Problem?
Während ich dies mit großen MyISAM-Tabellen getestet habe, sehe ich ähnliche Effekte mit denselben Tabellen, die in InnoDB konvertiert wurden (obwohl nicht so schlecht, dauert die Beispielabfrage immer noch 20 bis 30 Sekunden, wobei die meiste Zeit für das Lesen der Festplatte aufgewendet wird eine Warteschlangenlänge von 1) nach dem Neustart des MySQL-Daemons und daher sind die Pufferpools leer. Ich habe auch überprüft, dass das gleiche Problem bei 5.6 GA und dem aktuellen 5.7-Meilenstein 14 weiterhin besteht. Solange ich einen einzelnen Abfragethread verwende, scheint MySQL nicht in der Lage zu sein, die für die Abfrageverarbeitung erforderlichen E / A-Vorgänge zu parallelisieren.
Auf Anfrage einige zusätzliche Details zum Szenario. Das Verhalten kann mit einer Vielzahl von Abfragetypen beobachtet werden. Ich habe willkürlich einen für weitere Tests ausgewählt, der ungefähr so lautet:
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;
Ich weiß, dass es Raum für Optimierungen gibt, aber ich habe mich aus mehreren Gründen entschlossen, dies zu belassen und mich darauf zu konzentrieren, eine allgemeine Erklärung für das unerwartete E / A-Muster zu finden, das ich sehe.
Die verwendeten Tabellen enthalten eine Reihe von Daten:
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)
Wenn ich jetzt die obige Abfrage über diese Tabellen ausführe, erhalte ich Ausführungszeiten von über 1 Minute, während das System anscheinend ständig damit beschäftigt ist, Daten von der Festplatte mit einem einzelnen Thread zu lesen.
Das Profil für eine Beispielabfrageausführung (die in diesem Beispiel 1 Minute und 9,17 Sekunden dauerte) sieht folgendermaßen aus:
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)