Lector de planes de MySQL
Pega lo que te devuelve EXPLAIN o EXPLAIN ANALYZE y lee qué hace la consulta, paso a paso. Pega dos planes para compararlos: antes y después de un índice.
Lee los cuatro formatos de MySQL 8 tal como los copia el cliente mysql: la tabla de siempre, la vertical (con \G), FORMAT=JSON y el árbol de EXPLAIN ANALYZE o FORMAT=TREE. Distingue lo que MySQL estima de lo que midió: EXPLAIN es el plan antes de ejecutar; sólo EXPLAIN ANALYZE dice cuánto tardó y cuántas filas salieron de verdad. Si pegas también el SQL, revisa las pistas que le quitan decisiones al optimizador (FORCE INDEX, STRAIGHT_JOIN) y los patrones que suelen impedir un índice. Lo que pegues se lee en tu navegador y no se envía a ningún lado.
Abre con un caso: una tabla anual de transacciones con 8,040,017 filas, una consulta que trae las de una operación ordenadas por fecha, y dos planes. En el primero, la tabla de transacciones entraba por un índice de productos y estimaba pocas filas en ese paso; el segundo, con un índice por operación y fecha y las pistas FORCE INDEX y STRAIGHT_JOIN, empezaba con más. Los planes del ejemplo son hipotéticos, inspirados en el caso: de él vienen las referencias de 1,792 y de 54,898 filas y los 4.5 ms medidos en una prueba de laboratorio, no en producción; todo lo demás es de la simulación, y los nombres de tablas y columnas son genéricos.
Cuando la tabla crece
Un modelo, no una medición: cuántas filas toca la consulta «las transacciones de una operación, ordenadas por fecha, de 50 en 50» según cómo la resuelva MySQL, y cómo cambia eso cuando la tabla crece. El tiempo sale de multiplicar las filas por unos microsegundos supuestos por paso (abajo, en «Cómo calcula»); sirve para ver la forma de cada curva, no para predecir milisegundos en tu servidor.
FILAS TOCADAS SEGÚN EL TAMAÑO DE LA TABLA
Las dos escalas son logarítmicas. La línea vertical es el tamaño que pusiste arriba.
Cómo calcula
Con EXPLAIN (tabla, vertical o JSON), las filas de cada paso son la estimación de MySQL, sacada de sus estadísticas. Para el total se multiplica como en un nested loop: las filas que salen de un paso, ya aplicado el porcentaje filtrado, son las vueltas del siguiente. Es una aproximación a cuánto trabajo planea MySQL, antes de cualquier LIMIT; sólo cuenta el primer SELECT del plan.
Con EXPLAIN ANALYZE, cada paso trae lo estimado y lo medido: el tiempo hasta la primera fila y hasta la última (en milisegundos, por vuelta), las filas reales y las vueltas. El tiempo es el de ejecutar el plan, en la raíz, dentro de MySQL: no incluye optimizar la consulta, la red, la aplicación ni mandar las filas. Si MySQL esperaba diez veces más o menos filas de las que salieron, lo señala, porque con estimaciones así el optimizador puede escoger mal el orden; con un LIMIT arriba, que salgan menos filas de las estimadas no es un error.
«Using temporary» y «Using filesort» no se marcan como errores: ordenar o agrupar pocas filas es lo razonable. Pesan cuando entran muchas filas para devolver pocas, y eso es lo que la herramienta dice. FORCE INDEX y STRAIGHT_JOIN sirven para investigar si otro plan es mejor; dejarlos en el código congela una decisión que el optimizador ya no podrá corregir cuando los datos cambien.
El modelo de crecimiento compara tres maneras de resolver la misma consulta, siempre con la tabla de transacciones primero: así MySQL 8 la ordena antes de unir y sólo une los catálogos a las filas que llegan a la página. Sin índice útil, recorre la tabla completa, se queda con las filas de la operación y las ordena. Con un índice sólo por operación, encuentra esas filas directo, pero tiene que ordenarlas todas antes de cortar. Con el índice (operación, fecha), las lee ya en orden y para al llenar la página; para la página N lee también las de las páginas anteriores, (N − 1) × filas por página, porque OFFSET también se lee. Supuestos, en microsegundos: 0.15 por fila leída en secuencia, 1.5 por búsqueda en un índice, 0.4 × log₂ de las filas que ordena por cada una, y 1.0 por cada catálogo unido. Por eso el índice compuesto da décimas de milisegundo en el modelo y 4.5 ms en la medición de laboratorio del caso: el modelo no sabe de disco, memoria ni lo que cuesta de verdad cada búsqueda.
Lo que no modela: no es un benchmark ni sabe de tu servidor, tu memoria o tu disco; no ve bloqueos ni el costo de un índice en las escrituras; y lee lo que pegas, que es el plan para esos valores en ese momento. Un índice bueno para una consulta puede no serlo para otra: hay que probar con datos de un volumen parecido al de producción.