Toda aplicación necesita, tarde o temprano, guardar datos que sobrevivan al reinicio del proceso. La decisión sobre cómo y dónde persistir esos datos es una de las más influyentes y duraderas de cualquier arquitectura: condiciona el rendimiento, la escalabilidad, la consistencia y hasta el coste de operación. Durante décadas la respuesta por defecto fue "una base de datos relacional", pero la explosión de aplicaciones web a gran escala popularizó un abanico de alternativas agrupadas bajo el término NoSQL. En esta lección aprenderás las diferencias reales entre ambos mundos, qué garantías ofrecen (ACID frente a BASE), qué familias de bases NoSQL existen y, sobre todo, qué criterios objetivos usar para elegir. El objetivo no es declarar un ganador, sino que sepas razonar la decisión.

Contenido

  1. El modelo relacional (SQL) en esencia
  2. Qué significa realmente "NoSQL"
  3. Las cuatro familias NoSQL: documental, clave-valor, columnar y grafo
  4. Garantías transaccionales: ACID frente a BASE
  5. Tabla comparativa SQL vs NoSQL
  6. Criterios de elección y antipatrones
  7. Persistencia políglota

  1. El modelo relacional (SQL) en esencia

Una base de datos relacional organiza los datos en tablas (relaciones) formadas por filas y columnas, con un esquema rígido definido de antemano. Las relaciones entre tablas se expresan mediante claves foráneas, y consultamos los datos con SQL (Structured Query Language). Ejemplos: PostgreSQL, MySQL, Oracle, SQL Server.

Veamos un esquema relacional sencillo para clientes y sus pedidos:

-- Tabla de clientes: cada cliente tiene un identificador único
CREATE TABLE clientes (
    id          BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    nombre      VARCHAR(120) NOT NULL,
    email       VARCHAR(180) NOT NULL UNIQUE,
    creado_en   TIMESTAMP    NOT NULL DEFAULT now()
);

-- Tabla de pedidos: la columna cliente_id "apunta" a clientes.id
CREATE TABLE pedidos (
    id          BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    cliente_id  BIGINT       NOT NULL REFERENCES clientes(id),
    total       NUMERIC(10,2) NOT NULL CHECK (total >= 0),
    estado      VARCHAR(20)  NOT NULL DEFAULT 'PENDIENTE'
);

Analicemos el código fragmento a fragmento:

  • PRIMARY KEY GENERATED ALWAYS AS IDENTITY: define la clave primaria, el identificador único de cada fila. La base la genera automáticamente, así que nunca habrá dos clientes con el mismo id.
  • UNIQUE en email: la base garantiza que no se repita ningún correo. Es una regla de integridad que vive en los datos, no en el código de la aplicación.
  • REFERENCES clientes(id): declara una clave foránea. La base impide insertar un pedido cuyo cliente_id no exista, evitando "pedidos huérfanos". Esto se llama integridad referencial.
  • CHECK (total >= 0): una restricción que rechaza totales negativos. De nuevo, la regla la aplica el motor.

Para recuperar los pedidos de un cliente combinamos ambas tablas con un JOIN:

SELECT c.nombre, p.id AS pedido_id, p.total
FROM clientes c
JOIN pedidos p ON p.cliente_id = c.id   -- une filas que comparten el id
WHERE c.email = '[email protected]'
ORDER BY p.total DESC;

El JOIN es la operación estrella del modelo relacional: permite componer datos normalizados (sin duplicación) en el momento de la consulta. La fortaleza es la flexibilidad para hacer preguntas no previstas; el coste es que los JOIN muy grandes pueden ser lentos y difíciles de escalar horizontalmente.

  1. Qué significa realmente "NoSQL"

"NoSQL" es un nombre desafortunado: no significa "sin SQL" (muchas de estas bases ofrecen lenguajes de consulta parecidos) sino "Not Only SQL". Agrupa motores que renuncian total o parcialmente al modelo relacional para ganar en escalabilidad horizontal, flexibilidad de esquema o rendimiento en accesos concretos. Sus rasgos habituales:

  • Esquema flexible: cada registro puede tener campos distintos sin migraciones previas.
  • Escalado horizontal nativo: están diseñadas para repartir datos entre muchos nodos (sharding) desde el primer día.
  • Desnormalización: en lugar de JOIN, se duplican datos para que cada lectura toque un solo registro.
  • Garantías relajadas: a menudo sacrifican consistencia inmediata a cambio de disponibilidad y velocidad.

  1. Las cuatro familias NoSQL

No todas las bases NoSQL son iguales. Se clasifican en cuatro grandes familias según su modelo de datos:

3.1 Documental

Almacenan documentos autocontenidos, normalmente en JSON/BSON. Cada documento agrupa toda la información relacionada. Ejemplos: MongoDB, Couchbase. El mismo cliente con sus pedidos del ejemplo SQL se vería así en un único documento:

{
  "_id": "cli_1042",
  "nombre": "Ana López",
  "email": "[email protected]",
  "pedidos": [
    { "pedido_id": "ped_5001", "total": 49.90, "estado": "ENVIADO" },
    { "pedido_id": "ped_5002", "total": 12.50, "estado": "PENDIENTE" }
  ]
}

Observa la diferencia clave frente a SQL:

  • Los pedidos están embebidos dentro del cliente, en un array pedidos. Para mostrar la ficha del cliente con sus pedidos basta una sola lectura, sin JOIN.
  • No hay esquema fijo: otro cliente podría no tener el campo pedidos, o tener un campo telefono adicional, sin que nadie tenga que alterar la "tabla".
  • El precio de esta comodidad es la duplicación: si el nombre de un producto cambia y está copiado en miles de documentos, hay que actualizarlos todos.

3.2 Clave-valor

El modelo más simple: un diccionario gigante que asocia una clave a un valor opaco. Ejemplos: Redis, DynamoDB (en su uso básico). Ideal para sesiones, cachés y contadores. Pseudocódigo de acceso:

SET sesion:abc123  "{usuarioId: 1042, expira: 1700000000}"
GET sesion:abc123

Es extremadamente rápido porque la operación es un acceso directo por clave, pero no se puede consultar por el contenido del valor: solo se busca por la clave exacta.

3.3 Columnar (wide-column)

Almacenan los datos por columnas/familias de columnas en lugar de por filas, optimizadas para escrituras masivas y lecturas de rangos enormes. Ejemplos: Apache Cassandra, HBase. Brillan en series temporales y registros de eventos a escala de petabytes.

3.4 Grafo

Modelan entidades (nodos) y sus relaciones (aristas) como ciudadanos de primera clase. Ejemplos: Neo4j, Amazon Neptune. Cuando lo importante son las relaciones profundas (redes sociales, detección de fraude, recomendaciones, "amigos de amigos"), recorren conexiones de forma muchísimo más eficiente que un JOIN recursivo en SQL.

  1. Garantías transaccionales: ACID frente a BASE

Aquí está la diferencia conceptual más importante. Una transacción es un conjunto de operaciones que deben tratarse como una unidad.

ACID (propio del mundo relacional) garantiza:

Letra Propiedad Significado
A Atomicidad Todo o nada: o se aplican todas las operaciones o ninguna.
C Consistencia La base pasa de un estado válido a otro válido (se respetan restricciones).
I Aislamiento Las transacciones concurrentes no se pisan entre sí.
D Durabilidad Una vez confirmada, sobrevive a caídas del sistema.

Ejemplo clásico: transferir dinero entre dos cuentas debe ser atómico.

BEGIN;                                              -- inicia la transacción
UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1; -- resta de la cuenta origen
UPDATE cuentas SET saldo = saldo + 100 WHERE id = 2; -- suma a la cuenta destino
COMMIT;                                             -- confirma ambas a la vez

Si el sistema cae entre los dos UPDATE, la atomicidad asegura que ninguno se aplica: el dinero nunca "desaparece". Esta garantía es indispensable en banca, contabilidad o seguros.

BASE (frecuente en NoSQL distribuido) es el enfoque opuesto, pensado para sistemas que priorizan la disponibilidad a gran escala:

  • Basically Available: el sistema siempre responde, aunque sea con datos algo antiguos.
  • Soft state: el estado puede cambiar con el tiempo sin nuevas escrituras (por la propagación entre nodos).
  • Eventually consistent: si dejan de llegar escrituras, todos los nodos acabarán convergiendo al mismo valor, pero durante un breve intervalo pueden diferir.

La elección entre ACID y BASE está ligada al teorema CAP (visto en el Módulo 4): ante una partición de red, un sistema distribuido debe elegir entre consistencia y disponibilidad. ACID tiende a privilegiar la consistencia; BASE, la disponibilidad.

  1. Tabla comparativa SQL vs NoSQL

Aspecto SQL (relacional) NoSQL (genérico)
Modelo de datos Tablas con esquema fijo Documentos, clave-valor, columnas o grafos
Esquema Rígido, definido antes Flexible, dinámico
Relaciones JOIN e integridad referencial Desnormalización / embebido
Transacciones ACID completas A menudo BASE / ACID limitado
Escalado Principalmente vertical Horizontal nativo
Lenguaje SQL estándar Variado por motor
Consultas ad-hoc Excelente Limitado (depende del diseño previo)
Mejor para Datos estructurados con reglas fuertes Gran volumen, alta escala, esquema cambiante

  1. Criterios de elección y antipatrones

No elijas por moda. Hazte estas preguntas:

  1. ¿Tus datos tienen relaciones complejas y reglas de integridad fuertes? → SQL.
  2. ¿Necesitas consultas ad-hoc impredecibles? → SQL (los JOIN te salvan).
  3. ¿Tienes un patrón de acceso muy conocido y un volumen enorme? → NoSQL diseñado a medida de ese patrón.
  4. ¿El esquema evoluciona constantemente y los datos son semiestructurados? → documental.
  5. ¿Lo crítico son las relaciones (recorridos profundos)? → grafo.
  6. ¿Necesitas accesos ultrarrápidos por clave (sesiones, caché)? → clave-valor.

Errores Comunes y Consejos

  • Elegir NoSQL "porque escala" sin tener problema de escala. La mayoría de aplicaciones nunca alcanza el volumen donde el escalado horizontal compensa la pérdida de JOIN y transacciones. Empieza por SQL salvo que tengas una razón clara.
  • Modelar un documento como si fuera una tabla. Si en NoSQL documental acabas haciendo "JOIN a mano" en el código, has elegido mal el modelo o el diseño del documento.
  • Creer que NoSQL no tiene esquema. Sí lo tiene, solo que vive en tu código en lugar de en la base. Esto traslada la responsabilidad de validación a la aplicación.
  • Asumir que "eventual consistency" es inofensivo. En un saldo bancario o un stock, leer un dato obsoleto puede ser un error grave. Conoce tus requisitos de consistencia.
  • Consejo: mide antes de migrar. Un índice bien puesto en SQL resuelve muchísimos problemas de rendimiento atribuidos erróneamente al "modelo relacional".

Ejercicios

Ejercicio 1. Tienes una aplicación de banca que registra movimientos de cuentas y debe garantizar que nunca se pierda ni se duplique dinero. ¿SQL o NoSQL? Justifica con dos propiedades concretas.

Ejercicio 2. Diseña, en JSON, un documento para un perfil de usuario de una red social que incluya sus datos básicos y una lista de sus tres últimas publicaciones embebidas. Indica qué problema de mantenimiento introduces al embeber las publicaciones.

Ejercicio 3. Para un catálogo de productos donde cada categoría tiene atributos completamente distintos (un libro tiene "autor", un televisor tiene "pulgadas"), ¿qué familia de base de datos encaja mejor y por qué?

Soluciones

Solución 1. SQL relacional con transacciones ACID. Razones: la atomicidad garantiza que un movimiento (cargo + abono) se aplique entero o no se aplique, y la durabilidad asegura que una vez confirmado sobrevive a una caída. Además la integridad referencial y las restricciones CHECK evitan estados inválidos como saldos negativos no permitidos.

Solución 2. Documento de ejemplo:

{
  "_id": "usr_77",
  "nombre": "Marc Riera",
  "bio": "Aficionado a la fotografía",
  "publicaciones_recientes": [
    { "id": "pub_901", "texto": "¡Buenos días!", "likes": 12 },
    { "id": "pub_900", "texto": "Foto del atardecer", "likes": 48 }
  ]
}

Problema de mantenimiento: las publicaciones están duplicadas. Si una publicación se edita o cambia su número de likes, hay que actualizarla tanto en su colección original como dentro de cada documento de usuario que la embeba, con riesgo de incoherencias.

Solución 3. Una base documental. Su esquema flexible permite que cada producto tenga exactamente los atributos de su categoría sin columnas vacías ni tablas separadas por tipo, algo que en SQL obligaría a esquemas EAV incómodos o a muchas tablas.

Conclusión

Has aprendido que SQL y NoSQL no son rivales, sino herramientas con compromisos distintos: SQL aporta esquema fuerte, JOIN flexibles y garantías ACID; NoSQL aporta esquema flexible, escalado horizontal y, a cambio, suele relajar la consistencia (BASE). Conoces las cuatro familias NoSQL y un conjunto de criterios para decidir, recordando que muchas arquitecturas modernas adoptan persistencia políglota (usar la herramienta adecuada para cada necesidad). Una vez decidido dónde guardar los datos, la siguiente pregunta es cómo estructurar el código que accede a ellos sin ensuciar la lógica de negocio. Eso lo veremos en la próxima lección: Patrones de Acceso a Datos: Repository, Unit of Work y DAO.

Curso de Arquitectura de Aplicaciones

Módulo 1: Fundamentos de la Arquitectura de Aplicaciones

Módulo 2: Principios y Tácticas de Diseño

Módulo 3: Estilos y Patrones Arquitectónicos

Módulo 4: Arquitecturas Distribuidas y Microservicios

Módulo 5: Arquitecturas Dirigidas por Eventos y Mensajería

Módulo 6: Diseño Dirigido por el Dominio (DDD)

Módulo 7: Datos y Persistencia

Módulo 8: Arquitectura en la Nube y Despliegue

Módulo 9: Calidad, Seguridad y Observabilidad

Módulo 10: Evolución, Gobernanza y Casos Prácticos

© Copyright 2026. Todos los derechos reservados