Toda aplicación web almacena datos. Ya utilices PostgreSQL, MySQL, SQLite o SQL Server, necesitas dominar el lenguaje SQL. Incluso si dependes de un ORM como Prisma o Sequelize, comprender el SQL que generan es fundamental para depurar consultas lentas y diseñar esquemas eficientes.

Las Cuatro Grandes: Operaciones CRUD

Toda interacción con la base de datos se resume en cuatro operaciones fundamentales: Crear, Leer, Actualizar y Eliminar (CRUD por sus siglas en inglés).

CRUD en SQL
-- CREAR (Insertar)
INSERT INTO usuarios (nombre, email, rol)
VALUES ('Ana', '[email protected]', 'administrador');

-- LEER (Seleccionar)
SELECT id, nombre, email
FROM usuarios
WHERE rol = 'administrador'
ORDER BY nombre ASC
LIMIT 10;

-- ACTUALIZAR
UPDATE usuarios
SET rol = 'editor', actualizado_en = NOW()
WHERE id = 42;

-- ELIMINAR
DELETE FROM usuarios
WHERE id = 42;

Entendiendo los JOINs

Los JOINs combinan filas de dos o más tablas basándose en una columna relacionada. Esta es la esencia de las bases de datos relacionales.

INNER JOIN

Devuelve solo las filas que tienen una coincidencia en ambas tablas. Es ideal para obtener datos donde existe una relación explícita.

INNER JOIN
SELECT u.nombre, o.total, o.fecha_creacion
FROM usuarios u
INNER JOIN pedidos o ON u.id = o.usuario_id
WHERE o.total > 100;

LEFT JOIN

Devuelve todas las filas de la tabla izquierda y las filas coincidentes de la tabla derecha. Si no hay coincidencia en la tabla derecha, las columnas correspondientes serán NULL. Es perfecto para encontrar elementos que podrían no tener una contraparte, como usuarios sin pedidos registrados.

LEFT JOIN — Encontrar usuarios sin pedidos
SELECT u.nombre, COUNT(o.id) AS cantidad_pedidos
FROM usuarios u
LEFT JOIN pedidos o ON u.id = o.usuario_id
GROUP BY u.id, u.nombre
HAVING COUNT(o.id) = 0;

Índices: La Herramienta de Rendimiento #1

Un índice es similar al índice de un libro: permite a la base de datos encontrar filas sin tener que escanear cada una de ellas en la tabla (un "full table scan"). Sin índices, una consulta en una tabla con 10 millones de filas debe revisar las 10 millones de filas.

Creando Índices
-- Índice de columna única
CREATE INDEX idx_usuarios_email ON usuarios(email);

-- Índice compuesto (el orden de las columnas importa)
CREATE INDEX idx_pedidos_usuario_fecha ON pedidos(usuario_id, fecha_creacion);

-- Índice único (garantiza unicidad)
CREATE UNIQUE INDEX idx_usuarios_email_unico ON usuarios(email);

Regla general: Crea índices en las columnas que aparecen en las cláusulas WHERE, JOIN y ORDER BY. Pero no abuses de los índices, ya que cada uno ralentiza las operaciones de INSERT y UPDATE.

Consejos de Optimización de Consultas

  • Utiliza EXPLAIN (o EXPLAIN ANALYZE en PostgreSQL) para ver cómo la base de datos ejecuta tu consulta. Busca escaneos secuenciales en tablas grandes.
  • Selecciona solo las columnas que necesitas. SELECT * recupera todas las columnas, incluyendo campos BLOB y de texto que no utilizas.
  • Usa LIMIT para consultas paginadas en lugar de recuperar todas las filas.
  • Evita las consultas N+1. En lugar de consultar usuarios y luego iterar sobre cada usuario para consultar sus pedidos, utiliza un JOIN o una subconsulta.
  • Usa consultas parametrizadas para prevenir la inyección SQL y permitir que la base de datos almacene en caché los planes de consulta.
  • Normaliza tu esquema para evitar la duplicación de datos, pero desnormaliza tablas con muchas lecturas cuando el rendimiento lo requiera.

Transacciones: Todo o Nada

Ejemplo de Transacción
BEGIN;

UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;
UPDATE cuentas SET saldo = saldo + 100 WHERE id = 2;

-- Si ambos tienen éxito:
COMMIT;

-- Si algo falla:
ROLLBACK;

Las transacciones garantizan que un conjunto de operaciones o se completen todas con éxito, o fallen todas. Esto es esencial para operaciones financieras, gestión de inventario y cualquier escenario donde las actualizaciones parciales dejarían los datos en un estado inconsistente.

Errores Comunes a Evitar

  • No usar índices en columnas usadas en cláusulas WHERE y JOIN.
  • Usar SELECT * en consultas de producción.
  • Concatenación de cadenas en consultas — usa siempre consultas parametrizadas para prevenir la inyección SQL.
  • Falta de restricciones de clave foránea — deja que la base de datos imponga la integridad referencial.
  • No establecer tipos de datos apropiados — usa INTEGER para IDs, TIMESTAMPTZ para fechas, TEXT vs VARCHAR adecuadamente.

Prueba Nuestras Herramientas Gratuitas para Desarrolladores

Formatea y minimiza tu código al instante en tu navegador.