Volver a MySQL Intermedio

Optimización Avanzada de Consultas en MySQL

Traza del Optimizador

-- Activar traza del optimizador SET SESSION optimizer_trace = 'enabled=on'; SELECT * FROM pedidos o JOIN clientes c ON o.cliente_id = c.id WHERE o.estado = 'pendiente' AND c.pais = 'MX'; SELECT * FROM information_schema.OPTIMIZER_TRACE\G SET SESSION optimizer_trace = 'enabled=off';

Estrategias de Índices

-- Índice parcial con columna virtual ALTER TABLE usuarios ADD COLUMN email_lower VARCHAR(255) GENERATED ALWAYS AS (LOWER(email)) VIRTUAL, ADD INDEX idx_email_lower (email_lower); -- Índice multivalor en arrays JSON (MySQL 8.0.17+) CREATE TABLE eventos ( id INT PRIMARY KEY, etiquetas JSON ); CREATE INDEX idx_etiquetas ON eventos ((CAST(etiquetas AS CHAR(100) ARRAY))); SELECT * FROM eventos WHERE 'mysql' MEMBER OF (etiquetas);

Funciones de Ventana para Analítica

SELECT fecha_pedido, monto, SUM(monto) OVER ( PARTITION BY cliente_id ORDER BY fecha_pedido ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS total_acumulado, RANK() OVER (PARTITION BY cliente_id ORDER BY monto DESC) AS ranking_monto, LAG(monto, 1) OVER (PARTITION BY cliente_id ORDER BY fecha_pedido) AS monto_anterior FROM pedidos;

CTEs Recursivas

WITH RECURSIVE arbol_categorias AS ( SELECT id, nombre, padre_id, 1 AS profundidad FROM categorias WHERE padre_id IS NULL UNION ALL SELECT c.id, c.nombre, c.padre_id, ac.profundidad + 1 FROM categorias c JOIN arbol_categorias ac ON c.padre_id = ac.id WHERE ac.profundidad < 10 ) SELECT * FROM arbol_categorias ORDER BY profundidad, nombre;

Sugerencias al Optimizador

-- Forzar un índice específico SELECT /*+ INDEX(o idx_pedidos_estado_fecha) */ * FROM pedidos o WHERE estado = 'pendiente'; -- Definir orden de JOIN SELECT /*+ JOIN_ORDER(c, o, oi) */ * FROM clientes c JOIN pedidos o ON c.id = o.cliente_id JOIN detalle_pedido oi ON o.id = oi.pedido_id;

Errores Comunes que Rompen Índices

-- ❌ Función sobre columna indexada SELECT * FROM usuarios WHERE YEAR(creado_en) = 2024; -- ✅ Usar predicado de rango SELECT * FROM usuarios WHERE creado_en >= '2024-01-01' AND creado_en < '2025-01-01'; -- ❌ Wildcard al inicio SELECT * FROM productos WHERE nombre LIKE '%tablet%'; -- ✅ Índice de texto completo ALTER TABLE productos ADD FULLTEXT INDEX ft_nombre (nombre, descripcion); SELECT * FROM productos WHERE MATCH(nombre, descripcion) AGAINST('tablet');