High Performance MySQL [Cap. 7: Funciones avanzadas de MySQL]

High Performance MySQL

Lo esencial
  • El particionado es un índice grueso: solo compensa cuando las consultas filtran por la clave de particionado.
  • Las vistas son consultas guardadas, no resultados guardados. MySQL no tiene vistas materializadas; las tablas de resumen cubren ese hueco.
  • Los triggers se ejecutan por fila, dentro de tu transacción y de forma invisible. Cómodos, y difíciles de depurar.
  • Los eventos son un cron dentro del servidor. Protégelos tú mismo contra ejecuciones solapadas.

Tablas particionadas

Una tabla particionada es una tabla lógica guardada como varias tablas físicas. Cada partición tiene su propio handler por debajo del servidor; una capa de particionado ligera dirige cada sentencia a las particiones correctas, de modo que el motor de almacenamiento solo ve tablas normales. Cada índice de la tabla existe por separado en cada partición, y todas las particiones usan el mismo motor.

Ayuda en unas pocas situaciones concretas:

  • Tablas enormes con un extremo caliente. Las filas recientes se leen constantemente y las antiguas rara vez; las particiones mantienen pequeña la parte caliente.
  • Borrados masivos baratos. Eliminar una partición entera con los datos del año pasado es una operación de metadatos, no millones de borrados de filas.
  • Mantenimiento por partición: reconstruir, comprobar o restaurar un trozo en lugar de toda la tabla.

Cómo se dirigen las sentencias

SENTENCIAQUÉ HACE LA CAPA DE PARTICIONADO
SELECTEl optimizador descarta las particiones que no pueden coincidir y luego lee el resto.
INSERTEvalúa la expresión de particionado y escribe en una partición.
DELETEEncuentra la partición que contiene la fila y borra ahí.
UPDATEActualiza in situ, o mueve la fila si los nuevos valores pertenecen a otra partición.

Los bloqueos dentro de una partición siguen las reglas normales de InnoDB (bloqueos de fila, no de partición).

Los esquemas habituales son RANGE (por rangos de fechas o de ids, la opción típica para series temporales), LIST (conjuntos de valores explícitos) y HASH o KEY (reparten las filas de forma uniforme para reducir los puntos calientes):

CREATE TABLE bug_events (
  id BIGINT NOT NULL,
  created_at DATETIME NOT NULL,
  PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (YEAR(created_at)) (
  PARTITION p2024 VALUES LESS THAN (2025),
  PARTITION p2025 VALUES LESS THAN (2026),
  PARTITION pmax  VALUES LESS THAN MAXVALUE
);

MySQL exige que las columnas de particionado formen parte de todas las claves únicas, y por eso created_at se suma a la clave primaria en el ejemplo anterior.

Qué sale mal con las particiones

  • Las consultas que no filtran por la clave visitan todas las particiones y buscan en la copia del índice de cada una. Eso puede ser más lento que no particionar.
  • Los valores de particionado NULL acaban en la primera partición, así que las búsquedas pueden tener que revisarla además de la esperada. Haz que la expresión no admita NULL.
  • Demasiadas particiones encarecen el enrutamiento y la apertura de tablas. Decenas está bien; miles son mala señal.
  • El descarte de particiones necesita un predicado reconocible. Filtra directamente por la columna (created_at >= '2025-01-01') y revisa la columna partitions de EXPLAIN para confirmar que solo aparecen las particiones esperadas.

Vistas

Una vista es una consulta con nombre; no guarda datos. MySQL la ejecuta de una de dos maneras. Con el algoritmo MERGE, la definición de la vista se integra en tu consulta, así que los filtros se combinan y los índices siguen aplicándose; es el camino eficiente. Con TEMPTABLE, el resultado de la vista se materializa primero en una tabla temporal y tu consulta lee de ahí. TEMPTABLE se fuerza siempre que la vista usa GROUP BY, DISTINCT, agregados, UNION o ciertas subconsultas, y significa que los filtros de fuera no pueden llegar a los índices de la tabla base.

Las vistas simples pueden ser actualizables, y WITH CHECK OPTION rechaza las escrituras a través de la vista que producirían filas que la propia vista no mostraría.

Las vistas rara vez aceleran las consultas. Su valor práctico es el control de acceso y la simplicidad: expón una vista sin las columnas sensibles y concede SELECT solo sobre la vista. MySQL no tiene vistas materializadas; el sustituto son las tablas de caché y de resumen del capítulo 4, refrescadas por un proceso programado o un evento.

Triggers

Los triggers ejecutan código BEFORE o AFTER de un INSERT, UPDATE o DELETE, dentro de la misma transacción que la sentencia. Esa atomicidad los hace prácticos para mantener sincronizadas columnas desnormalizadas o contadores de resumen sin viajes de ida y vuelta adicionales. MySQL 8 permite varios triggers por evento y tabla.

Los costes son reales:

  • Fila a fila. Los triggers de MySQL son siempre FOR EACH ROW; una sentencia que toca un millón de filas los dispara un millón de veces.
  • Trabajo invisible. Una sentencia de una línea puede hacer mucho entre bastidores, lo que distorsiona el perfilado y sorprende al siguiente desarrollador.
  • Bloqueos y fallos. Los triggers pueden provocar esperas de bloqueo y deadlocks inesperados, y sus errores hacen fallar la sentencia original con un mensaje que no apunta a ningún sitio evidente.

Eventos

Los eventos son SQL programado, un cron que vive en el servidor: se ejecutan una vez a una hora concreta o a intervalos. Mantén el cuerpo del evento mínimo y pon la lógica en un procedimiento almacenado. MySQL no impide que empiece una nueva ejecución mientras la anterior sigue en marcha, así que protege los trabajos largos con un bloqueo con nombre:

CREATE EVENT purge_old_bug_events
ON SCHEDULE EVERY 1 DAY
DO
  BEGIN
    IF GET_LOCK('purge_old_bug_events', 0) THEN
      CALL purge_old_bug_events();
      DO RELEASE_LOCK('purge_old_bug_events');
    END IF;
  END

El programador de eventos tiene que estar activado (event_scheduler=ON, el valor por defecto en MySQL 8), y los eventos solo se ejecutan en el servidor donde se definen, algo que importa cuando hay réplicas.

Dónde termina esta serie

El resto del libro pasa de la consulta a la máquina: configuración del servidor, sistema operativo y hardware, replicación, escalado, alta disponibilidad, copias de seguridad y recuperación. Todo eso importa, pero es sobre todo trabajo de operaciones, y los servicios gestionados de MySQL se encargan de buena parte de ello para los equipos de aplicación. Los capítulos 1 a 7 cubren lo que controlas desde el editor de consultas.

Preguntas frecuentes

¿Particionar acelerará mi consulta lenta?

Solo si la consulta filtra por la clave de particionado, de modo que se descarten particiones enteras. Si no, un índice mejor casi siempre ayuda más.

¿Una vista es más lenta que escribir la consulta completa?

Con el algoritmo MERGE es la misma consulta. Con TEMPTABLE puede ser mucho más lenta, porque los filtros externos no pueden usar los índices de la tabla base.

Fuente: Schwartz, Zaitsev y Tkachenko, High Performance MySQL, capítulo 7: Advanced MySQL Features, con notas actualizadas para MySQL 8. Son nuestras notas, no un sustituto del libro.