7 errores críticos que todos cometen con SQL (y cómo arreglarlos)

sql 7 errores críticos que todos cometen con SQL (y cómo arreglarlos)

7 errores críticos que todos cometen con SQL (y cómo arreglarlos)

Este artículo señala errores frecuentes en SQL —tanto de rendimiento como de seguridad y lógica— con ejemplos prácticos, cómo detectarlos y soluciones concretas. Ve al grano: código, por qué falla y la corrección.

1) Usar SELECT * en producción

Problema: traer columnas que no necesitas aumenta I/O, red y CPU, y hace que cambios en el esquema afecten consultas.

-- Malo
SELECT * FROM users WHERE status = 'active';

-- Mejor: solo lo necesario
SELECT id, email, last_login FROM users WHERE status = 'active';

Por qué: reduces ancho de banda y lecturas de disco, y mejoras uso de índices (si los índices cubren las columnas seleccionadas).

2) No tener (o tener mal) índices

Problema: consultas que escanean la tabla completa (table scan). Detecta con EXPLAIN o EXPLAIN ANALYZE.

-- Malo: sin índice en user_id
SELECT * FROM orders WHERE user_id = 12345;

-- Solución: crear índice
CREATE INDEX idx_orders_user_id ON orders(user_id);

Por qué: los índices aceleran búsquedas, JOINs y ORDER BY. Pero cuidado: demasiados índices afectan INSERT/UPDATE/DELETE y ocupan espacio.

3) No usar transacciones para operaciones múltiples

Problema: en operaciones que requieren atomicidad (transferencias, inserciones relacionadas), si algo falla quedas con datos inconsistentes.

-- Malo: operaciones separadas
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- Bueno: transacción
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

-- En caso de error: ROLLBACK

Por qué: las transacciones garantizan atomicidad, consistencia y aislamiento (ACID). Usa niveles de aislamiento apropiados según la necesidad.

4) Construir consultas concatenando strings (riesgo de SQL Injection)

Problema: entradas del usuario inyectadas en la consulta permiten ejecución arbitraria.

-- Muy malo (vulnerable)
query = "SELECT * FROM users WHERE email = '" + email + "'";

-- Correcto: consultas parametrizadas
-- Ejemplo con PDO (PHP)
$stmt = $pdo->prepare('SELECT id, email FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();

Por qué: usar parámetros evita que datos de usuario sean interpretados como SQL. En ORMs y drivers modernos siempre usa parámetros/prepared statements.

5) Ignorar NULLs y comparaciones erróneas

Problema: comparar NULL con = o asumir que NULL = NULL es verdadero produce resultados inesperados.

-- Malo
SELECT * FROM products WHERE discontinued = NULL; -- nunca retornará filas

-- Correcto
SELECT * FROM products WHERE discontinued IS NULL;

-- Para actualizar evitando NULLs
UPDATE products SET stock = COALESCE(stock, 0) + 5 WHERE id = 1;

Por qué: NULL representa información desconocida; usa IS NULL/IS NOT NULL y funciones como COALESCE para controlarlo.

6) Patrón N+1 en aplicaciones (consultas repetidas por fila)

Problema: una consulta principal seguida de N consultas adicionales dentro de un bucle —multiplica llamadas a la DB y degrada rendimiento.

-- Malo: por cada post haces una consulta para autor
SELECT * FROM posts LIMIT 20;
-- en código: por cada post -> SELECT * FROM users WHERE id = post.author_id;

-- Mejor: hacer JOIN o batch
SELECT p.id, p.title, u.id AS author_id, u.name
FROM posts p
JOIN users u ON u.id = p.author_id
LIMIT 20;

Por qué: reduce round-trips y aprovecha la capacidad de la DB para combinar datos eficientemente. Si usas ORM, aprende sus mecanismos de eager loading (JOIN/fetch).

7) ORDER BY/GROUP BY sin soporte de índice o en grandes volúmenes

Problema: ordenar o agrupar columnas grandes provoca ordenamiento en disco y consumo de recursos.

-- Malo: ordenando por texto largo sin índice adecuado
SELECT * FROM logs ORDER BY created_at DESC LIMIT 100;

-- Mejor: índice compuesto si filtras y ordenas por columnas relacionadas
CREATE INDEX idx_logs_service_created ON logs(service, created_at DESC);

-- Para GROUP BY: asegúrate de agrupar por columnas indexadas o preagregar
SELECT user_id, COUNT(*) FROM events GROUP BY user_id;

Por qué: un índice adecuado puede cubrir ORDER BY y acelerar GROUP BY; en consultas analíticas, considera materialized views o tablas de agregados.

Cómo detectar estos problemas

  • Usa EXPLAIN/EXPLAIN ANALYZE para revisar planes de ejecución.
  • Activa el slow query log (MySQL) o revisa pg_stat_statements (Postgres).
  • Monitorea latencias y número de queries por endpoint (APM, logs).
  • Simula carga y perfila con datos reales o representativos.

Checklist rápido para producción

  • No usar SELECT *.
  • Revisar y mantener índices (evitar índices innecesarios).
  • Usar transacciones donde convenga.
  • Preparar consultas y parametrizar siempre entradas de usuarios.
  • Manejar NULL explícitamente.
  • Evitar N+1 usando JOINs o eager loading en ORMs.
  • Optimizar ORDER BY/GROUP BY o usar agregaciones precomputadas.

Consejo avanzado: cuando optimices, empieza por medir. Usa EXPLAIN ANALYZE para ver tiempos reales y revisa estadísticas del servidor (I/O, locks, buffers). Implementa cambios incrementales y verifica efecto en las métricas. Advertencia: añadir un índice puede mejorar lecturas pero penalizar escrituras; evalúa trade-offs según tu carga.

Siguiente paso sugerido: identifica 3 consultas lentas hoy, revisa su plan y aplica estas correcciones una por una; documenta resultados y ajusta índices en base a datos reales.

Comentarios
¿Quieres comentar?

Inicia sesión con Telegram para participar en la conversación


Comentarios (0)

Aún no hay comentarios. ¡Sé el primero en comentar!

Iniciar Sesión