TechLead
Leccion 13 de 30
7 min de lectura
Diseño de Sistemas

SQL vs NoSQL a Escala

Compara bases de datos SQL y NoSQL a escala incluyendo ACID vs BASE, almacenes de documentos, clave-valor, familia de columnas y bases de datos de grafos con marcos de decisión

SQL vs NoSQL: Las Compensaciones Fundamentales

Elegir la base de datos correcta es una de las decisiones más consecuentes en el diseño de sistemas. Las bases de datos SQL y NoSQL no son competidoras -- son herramientas diseñadas para diferentes problemas. Entender sus fortalezas, debilidades y características de escalado es esencial para diseñar sistemas que funcionen bien bajo carga.

Definiciones Rápidas

  • SQL (Relacional): Datos estructurados organizados en tablas con filas y columnas, con relaciones enforced a través de claves foráneas y joins. Ejemplos: PostgreSQL, MySQL, SQL Server.
  • NoSQL (No Relacional): Una categoría amplia que abarca almacenes de documentos, almacenes clave-valor, bases de datos de familia de columnas y bases de datos de grafos. Ejemplos: MongoDB, Redis, Cassandra, Neo4j.

ACID vs BASE

La diferencia fundamental en garantías entre las bases de datos SQL y NoSQL se puede resumir con dos acrónimos: ACID y BASE.

Propiedades ACID vs BASE

ACID (SQL) BASE (NoSQL)
Atomicidad - Transacciones de todo o nadaBásicamente Disponible - El sistema garantiza disponibilidad
Consistencia - Datos siempre válidos según restriccionesEstado suave - El estado puede cambiar con el tiempo sin entrada
Aislamiento - Las transacciones concurrentes no interfierenConsistencia eventual - El sistema eventualmente se volverá consistente
Durabilidad - Los datos confirmados sobreviven a fallosPrioriza disponibilidad y tolerancia a particiones
// Ejemplo de transacción ACID (SQL)
async function transferMoney(fromId: string, toId: string, amount: number) {
  const trx = await db.transaction();
  try {
    // Ambas operaciones tienen éxito o ambas fallan (Atomicidad)
    await trx.execute(
      "UPDATE accounts SET balance = balance - $1 WHERE id = $2 AND balance >= $1",
      [amount, fromId]
    );
    await trx.execute(
      "UPDATE accounts SET balance = balance + $1 WHERE id = $2",
      [amount, toId]
    );
    await trx.commit(); // Durabilidad: escrito a disco
  } catch (error) {
    await trx.rollback(); // Atomicidad: nada ocurrió
    throw error;
  }
}

// Enfoque BASE (NoSQL)
// La misma transferencia usando consistencia eventual
async function transferMoneyEventual(fromId: string, toId: string, amount: number) {
  // Debitar al remitente (puede tener éxito independientemente)
  await dynamodb.update({
    TableName: "accounts",
    Key: { id: fromId },
    UpdateExpression: "SET balance = balance - :amount",
    ConditionExpression: "balance >= :amount",
    ExpressionAttributeValues: { ":amount": amount },
  });

  // Acreditar al receptor (procesado asincrónicamente via evento)
  await sqs.sendMessage({
    QueueUrl: TRANSFER_QUEUE,
    MessageBody: JSON.stringify({ toId, amount, fromId }),
  });
  // Si esto falla, un proceso de reconciliación detectará
  // y corregirá la inconsistencia
}

Tipos de Bases de Datos NoSQL

1. Bases de Datos de Documentos

Almacenan datos como documentos semi-estructurados (JSON, BSON). Cada documento puede tener una estructura diferente, haciéndolos flexibles para esquemas en evolución. Los documentos se agrupan típicamente en colecciones.

  • Ejemplos: MongoDB, CouchDB, Firestore
  • Mejor para: Gestión de contenido, perfiles de usuario, catálogos de productos, cualquier dominio con estructuras de datos variadas o anidadas
  • Estilo de consulta: Lenguaje de consulta rico, índices secundarios, pipelines de agregación

2. Almacenes Clave-Valor

El modelo NoSQL más simple. Los datos se almacenan como pares clave-valor, como un hash map gigante. Extremadamente rápido para búsquedas por clave pero no ofrecen consulta por valor.

  • Ejemplos: Redis, DynamoDB, Memcached
  • Mejor para: Caché, gestión de sesiones, leaderboards en tiempo real, limitación de tasa
  • Estilo de consulta: GET/SET solo por clave (algunos soportan índices secundarios)

3. Almacenes de Familia de Columnas (Wide-Column)

Almacenan datos en columnas en lugar de filas. Cada fila puede tener un conjunto diferente de columnas. Optimizados para leer y escribir grandes volúmenes de datos a través de muchas máquinas.

  • Ejemplos: Cassandra, HBase, ScyllaDB
  • Mejor para: Datos de series de tiempo, datos IoT, logging de eventos, analíticas a escala masiva
  • Estilo de consulta: Limitado a consultas por clave de partición y columna de clustering

4. Bases de Datos de Grafos

Representan datos como nodos (entidades) y aristas (relaciones). Optimizados para recorrer relaciones complejas entre entidades.

  • Ejemplos: Neo4j, Amazon Neptune, ArangoDB
  • Mejor para: Redes sociales, motores de recomendación, detección de fraude, grafos de conocimiento
  • Estilo de consulta: Consultas de recorrido de grafos (Cypher, Gremlin, SPARQL)

Características de Escalado

Cómo Escalan las Diferentes Bases de Datos

Tipo de Base de Datos Escalado Vertical Escalado Horizontal Complejidad
SQL (PostgreSQL, MySQL)ExcelenteDifícil (sharding es manual)Alta para sharding
Documento (MongoDB)BuenoBueno (sharding incorporado)Media
Clave-Valor (Redis)BuenoBueno (Redis Cluster)Baja-Media
Familia de Columnas (Cassandra)BuenoExcelente (diseñado para ello)Baja
Grafos (Neo4j)BuenoLimitado (particionar grafos es difícil)Alta

Estrategias de Escalado SQL

  • Réplicas de lectura: Agregar réplicas para manejar tráfico de lectura (primer paso más común)
  • Pool de conexiones: Usar PgBouncer o ProxySQL para gestionar conexiones de base de datos eficientemente
  • Escalado vertical: Actualizar CPU, RAM y usar SSDs rápidos
  • Particionamiento / Sharding: Dividir datos a través de múltiples servidores de base de datos por una clave de shard
  • NewSQL: CockroachDB, TiDB y Vitess proporcionan interfaces SQL con escalado horizontal incorporado

Estrategias de Escalado NoSQL

  • Sharding nativo: La mayoría de las bases de datos NoSQL hacen sharding automáticamente basándose en una clave de partición
  • Consistencia ajustable: Ajustar niveles de consistencia por consulta (ej., lecturas de quórum en Cassandra)
  • Desnormalización: Almacenar datos en la forma que tus consultas necesitan para evitar joins
  • Estrategias de compactación: Optimizar configuraciones del motor de almacenamiento para tu patrón de escritura
// Modelando los mismos datos en SQL vs NoSQL

// SQL: Esquema normalizado (3NF)
// Tabla Users
// | id | name       | email            |
// | 1  | Alice      | alice@mail.com   |

// Tabla Orders
// | id | user_id | product_id | quantity | created_at |
// | 1  | 1       | 100        | 2        | 2025-01-15 |

// Tabla Products
// | id  | name     | price |
// | 100 | Widget   | 29.99 |

// Consulta SQL: Obtener usuario con sus pedidos y nombres de productos
// SELECT u.name, o.quantity, p.name as product_name, p.price
// FROM users u
// JOIN orders o ON u.id = o.user_id
// JOIN products p ON o.product_id = p.id
// WHERE u.id = 1;

// NoSQL (Documento): Desnormalizado para rendimiento de lectura
interface UserDocument {
  _id: string;
  name: string;
  email: string;
  orders: Array<{
    orderId: string;
    product: {
      productId: string;
      name: string;
      price: number;
    };
    quantity: number;
    createdAt: Date;
  }>;
}

// Una sola lectura para obtener todo - no se necesitan joins
// Pero actualizar el nombre de un producto requiere actualizar cada documento
// que referencia ese producto (compensación de desnormalización)

Marco de Decisión

Usa este marco al decidir entre SQL y NoSQL en entrevistas de diseño de sistemas o proyectos reales.

Elige SQL Cuando:

  • Los datos tienen relaciones claras y necesitas consultar a través de esas relaciones con JOINs
  • Las transacciones ACID son críticas (sistemas financieros, inventario, sistemas de reservas)
  • El esquema está bien definido y es improbable que cambie dramáticamente
  • Se necesitan consultas complejas con agregaciones, agrupamiento y filtrado en múltiples columnas
  • La integridad de datos es primordial (claves foráneas, restricciones únicas, restricciones de verificación)

Elige NoSQL Cuando:

  • Se necesita rendimiento masivo de escritura (logging, IoT, streams de eventos)
  • Los datos son naturalmente jerárquicos o anidados (documentos JSON, contenido generado por usuarios)
  • La flexibilidad de esquema es importante (iteración rápida, formas de datos variadas)
  • El escalado horizontal es un requisito primario desde el primer día
  • Patrones de acceso simples (búsqueda por clave, sin joins complejos)
  • Lecturas de baja latencia a cualquier escala (capa de caché, almacenamiento de sesiones)

Ejemplos del Mundo Real

Empresa/Caso de Uso Elección de Base de Datos Por Qué
Banca / PagosPostgreSQLTransacciones ACID para integridad financiera
Catálogo de Productos (Amazon)DynamoDBBúsquedas clave-valor a escala masiva, atributos de producto variados
Grafo Social (Facebook)TAO (tipo Grafo)Optimizado para recorrido de relaciones
Métricas de Series de TiempoCassandra / InfluxDBAlto rendimiento de escritura, particionamiento basado en tiempo
Almacenamiento de SesionesRedisLecturas sub-milisegundo, expiración automática
Pedidos de E-commercePostgreSQL + RedisSQL para integridad de pedidos, Redis para caché

Consejo de Entrevista: Persistencia Políglota

La mayoría de los sistemas del mundo real usan múltiples bases de datos para diferentes propósitos. En entrevistas, no te sientas obligado a elegir solo una. Un sistema bien diseñado podría usar PostgreSQL para datos de usuario y pedidos, Redis para caché y sesiones, Elasticsearch para búsqueda de texto completo, y Cassandra para logging de eventos. Este enfoque se llama persistencia políglota, y mencionarlo demuestra madurez arquitectónica.

Continuar Aprendiendo