Al mirar una consulta particularmente molesta sobre tablas MyISAM que lleva mucho tiempo ejecutar en varias ocasiones, noté que MySQL parece exponer un patrón de E / S bastante extraño: al ejecutar una sola consulta y tener que hacer una tarea significativa cantidad de E / S (por ejemplo, para un escaneo de tabla o cuando las memorias caché están vacías como resultado de echo 3 > /proc/sys/vm/drop_caches
lo cual los índices deben cargarse primero del disco), el tamaño de la cola para el dispositivo de bloque subyacente está cerca del valor 1, con un rendimiento abismal de solo 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
Si bien los 150 IOPS simplemente son lo que un solo disco en la configuración dada es capaz de entregar en términos de E / S aleatorias, el resultado todavía me sorprende, ya que esperaría que MySQL pueda ejecutar E / S asíncronas para lecturas y obtener un gran cantidad de bloques simultáneamente en lugar de leerlos y evaluarlos uno por uno, descuidando efectivamente las ganancias de paralelización disponibles en las configuraciones RAID. ¿Qué decisión de diseño u opción de configuración es responsable de esto? ¿Es este un problema específico de la plataforma?
Si bien he probado esto con tablas MyISAM de gran tamaño, veo efectos similares con las mismas tablas convertidas a InnoDB (aunque no es tan malo, la consulta de muestra todavía tarda 20-30 segundos y la mayor parte del tiempo se dedica a leer el disco con una longitud de cola de 1) después de reiniciar el demonio mysql y, por lo tanto, los grupos de búferes están vacíos. También verifiqué que el mismo problema persiste en 5.6 GA y el hito actual 5.7 5.7 - siempre que esté usando un solo hilo de consulta, MySQL parece incapaz de paralelizar las operaciones de E / S necesarias para el procesamiento de consultas.
Según la solicitud, algunos detalles adicionales sobre el escenario. El comportamiento se puede observar con una multitud de tipos de consulta. Elegí arbitrariamente uno para pruebas adicionales que dice algo así:
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;
Sé que tiene algo de espacio para la optimización, pero decidí dejarlo así por varias razones y concentrarme en encontrar una explicación general del inesperado patrón de E / S que estoy viendo.
Las tablas usadas tienen un montón de datos en ellas:
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)
Ahora, cuando ejecuto la consulta anterior sobre estas tablas, obtengo tiempos de ejecución de más de 1 minuto mientras el sistema aparentemente está continuamente ocupado leyendo datos del disco con un solo hilo.
El perfil para una ejecución de consulta de muestra (que tomó 1 min 9.17 segundos en este ejemplo) se ve así:
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)