Optimizar consultas SQL lentas


¿Por qué optimizar consultas SQL?

Las consultas SQL lentas pueden afectar significativamente el rendimiento de tu aplicación, causando tiempos de carga largos, timeouts y una mala experiencia de usuario. Optimizar estas consultas mejora la velocidad, reduce la carga del servidor y mejora la escalabilidad.


Identificar consultas lentas

1. Habilitar log de consultas lentas

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Agregá o modificá:

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow-query.log
long_query_time = 2

Reiniciá MySQL:

sudo systemctl restart mysql

2. Ver consultas lentas

sudo tail -f /var/log/mysql/slow-query.log

3. Usar EXPLAIN para analizar consultas

EXPLAIN SELECT * FROM usuarios WHERE email = '[email protected]';

Técnicas de optimización

1. Usar índices

Los índices son fundamentales para mejorar el rendimiento de las consultas.

Crear índices:

-- Índice simple
CREATE INDEX idx_email ON usuarios(email);

-- Índice único
CREATE UNIQUE INDEX idx_email_unique ON usuarios(email);

-- Índice compuesto
CREATE INDEX idx_nombre_edad ON usuarios(nombre, edad);

-- Índice en múltiples columnas
CREATE INDEX idx_busqueda ON productos(nombre, categoria, precio);

Ver índices existentes:

SHOW INDEXES FROM nombre_tabla;

Eliminar índices innecesarios:

DROP INDEX idx_nombre ON usuarios;

2. Optimizar consultas SELECT

Evitar SELECT *:

-- Malo
SELECT * FROM usuarios;

-- Bueno
SELECT id, nombre, email FROM usuarios;

Usar LIMIT:

-- Limitar resultados
SELECT * FROM productos ORDER BY fecha DESC LIMIT 10;

Usar WHERE apropiadamente:

-- Asegurate de que las columnas en WHERE tengan índices
SELECT * FROM usuarios WHERE email = '[email protected]';

3. Optimizar JOINs

Usar índices en columnas de JOIN:

-- Asegurate de que las columnas de JOIN tengan índices
SELECT u.nombre, p.titulo 
FROM usuarios u
INNER JOIN posts p ON u.id = p.usuario_id
WHERE u.activo = 1;

Evitar JOINs innecesarios:

-- Si solo necesitás datos de una tabla, no hagas JOIN
-- Malo
SELECT u.nombre FROM usuarios u JOIN posts p ON u.id = p.usuario_id;

-- Bueno (si solo necesitás usuarios)
SELECT nombre FROM usuarios WHERE id IN (SELECT usuario_id FROM posts);

4. Optimizar subconsultas

Convertir subconsultas a JOINs cuando sea posible:

-- Menos eficiente
SELECT * FROM usuarios 
WHERE id IN (SELECT usuario_id FROM posts WHERE activo = 1);

-- Más eficiente
SELECT DISTINCT u.* 
FROM usuarios u
INNER JOIN posts p ON u.id = p.usuario_id
WHERE p.activo = 1;

5. Usar UNION en lugar de OR cuando sea posible

-- Menos eficiente
SELECT * FROM productos WHERE categoria = 'A' OR categoria = 'B';

-- Más eficiente
SELECT * FROM productos WHERE categoria = 'A'
UNION
SELECT * FROM productos WHERE categoria = 'B';

6. Optimizar ORDER BY

Usar índices para ORDER BY:

-- Crear índice para ordenamiento
CREATE INDEX idx_fecha ON posts(fecha);

-- La consulta será más rápida
SELECT * FROM posts ORDER BY fecha DESC;

Evitar ORDER BY con funciones:

-- Menos eficiente
SELECT * FROM usuarios ORDER BY UPPER(nombre);

-- Más eficiente (si es posible)
SELECT * FROM usuarios ORDER BY nombre;

7. Optimizar GROUP BY

Usar índices en columnas de GROUP BY:

CREATE INDEX idx_categoria ON productos(categoria);

-- La consulta será más rápida
SELECT categoria, COUNT(*) FROM productos GROUP BY categoria;

8. Usar EXISTS en lugar de COUNT cuando sea posible

-- Menos eficiente
SELECT * FROM usuarios 
WHERE (SELECT COUNT(*) FROM posts WHERE usuario_id = usuarios.id) > 0;

-- Más eficiente
SELECT * FROM usuarios u
WHERE EXISTS (SELECT 1 FROM posts p WHERE p.usuario_id = u.id);

9. Evitar funciones en WHERE

-- Menos eficiente (no puede usar índice)
SELECT * FROM usuarios WHERE YEAR(fecha_registro) = 2024;

-- Más eficiente
SELECT * FROM usuarios 
WHERE fecha_registro >= '2024-01-01' AND fecha_registro < '2025-01-01';

10. Usar LIMIT con OFFSET eficientemente

-- Para paginación, considera usar cursor-based pagination
-- En lugar de:
SELECT * FROM productos ORDER BY id LIMIT 10 OFFSET 1000;

-- Usá:
SELECT * FROM productos WHERE id > 1000 ORDER BY id LIMIT 10;

Herramientas de análisis

1. EXPLAIN

EXPLAIN SELECT * FROM usuarios WHERE email = '[email protected]';

Revisá especialmente: - type: Debe ser ref o eq_ref, no ALL - key: Debe mostrar el índice usado - rows: Número de filas examinadas (debe ser bajo)

2. EXPLAIN ANALYZE (MySQL 8.0.18+)

EXPLAIN ANALYZE SELECT * FROM usuarios WHERE email = '[email protected]';

3. PROFILE

SET PROFILING = 1;
SELECT * FROM usuarios WHERE email = '[email protected]';
SHOW PROFILES;
SHOW PROFILE FOR QUERY 1;

Optimizar tablas

1. Analizar tablas regularmente

ANALYZE TABLE nombre_tabla;

2. Optimizar tablas

OPTIMIZE TABLE nombre_tabla;

3. Verificar y reparar tablas

CHECK TABLE nombre_tabla;
REPAIR TABLE nombre_tabla;

Configuración de MySQL para mejor rendimiento

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Parámetros importantes:

[mysqld]
# Memoria
innodb_buffer_pool_size = 1G
key_buffer_size = 256M
query_cache_size = 64M

# Consultas
max_connections = 200
thread_cache_size = 50
table_open_cache = 2000

# Logs
slow_query_log = 1
long_query_time = 2

Reiniciá MySQL después de los cambios.


Mejores prácticas

  • Usá índices estratégicamente: No crees índices en todas las columnas, solo en las que se usan frecuentemente en WHERE, JOIN y ORDER BY
  • Monitoreá consultas lentas: Revisá regularmente el log de consultas lentas
  • Probá cambios: Siempre probá las optimizaciones en un entorno de desarrollo primero
  • Documentá cambios: Guardá un registro de las optimizaciones realizadas
  • Hacé backups: Antes de hacer cambios importantes, hacé un backup
  • Actualizá estadísticas: Ejecutá ANALYZE TABLE regularmente

¿Necesitás ayuda?

Si tenés consultas SQL lentas y necesitás ayuda optimizándolas, abrí un ticket desde el panel de billing.baires.host o contactanos por soporte. Incluí la consulta problemática y el resultado de EXPLAIN.

También podés escribirnos por nuestras redes:

¿Fue útil la respuesta? 0 Los Usuarios han Encontrado Esto Útil (0 Votos)