Saltar al contenido principal

⚖️ SQL vs NoSQL

📖 Definición

SQL (bases de datos relacionales) almacena datos en forma de tabla con estructura fija y los manipula con lenguaje SQL. NoSQL (bases de datos no relacionales) almacena varios tipos de datos con esquema flexible y es ventajoso para la expansión horizontal. Cada uno tiene ventajas y desventajas, y debe elegirse según los requisitos del proyecto.

🎯 Comprensión a través de analogías

Biblioteca vs Almacén

SQL (BD relacional) = Biblioteca organizada
├─ Todos los libros clasificados en lugares fijos
├─ Información precisa registrada en fichas
├─ Reglas estrictas de préstamo/devolución
└─ Fácil de encontrar pero poco flexible

NoSQL (BD no relacional) = Almacén flexible
├─ Puede almacenar objetos de varias formas
├─ Adición/eliminación rápida
├─ Expansión de espacio fácil
└─ Flexible pero la organización puede ser difícil

Registro escolar vs Redes sociales

SQL = Registro de asistencia escolar
Tabla de estudiantes:
┌────┬─────────┬─────┬────────┐
│ ID │ Nombre │ Edad│ Clase │
├────┼─────────┼─────┼────────┤
│ 1 │ Juan │ 15 │ 1A │
│ 2 │ María │ 15 │ 2A │
└────┴─────────┴─────┴────────┘
- Todos los estudiantes tienen los mismos campos de información

NoSQL = Perfil de redes sociales
Usuario1: { name: "Juan", age: 15, hobbies: ["lectura", "juegos"] }
Usuario2: { name: "María", city: "Madrid", job: "estudiante", pets: 2 }
- Cada usuario puede tener diferente información

⚙️ Principio de funcionamiento

1. Comparación de estructuras de datos

-- SQL: Tablas estructuradas
Tabla users
┌────┬─────────┬──────────────────┬─────┐
│ id │ name │ email │ age │
├────┼─────────┼──────────────────┼─────┤
1 │ Juan │ juan@mail.com25
2 │ María │ maria@mail.com30
└────┴─────────┴──────────────────┴─────┘

Tabla orders
┌────┬─────────┬─────────────┬───────┐
│ id │ user_id │ product │ price │
├────┼─────────┼─────────────┼───────┤
11 │ Portátil │ 1500
21 │ Ratón │ 30
└────┴─────────┴─────────────┴───────┘
// NoSQL: Documentos flexibles
// Ejemplo de MongoDB
{
_id: ObjectId("507f1f77bcf86cd799439011"),
name: "Juan",
email: "juan@mail.com",
age: 25,
orders: [ // Documentos anidados
{
product: "Portátil",
price: 1500,
date: "2024-01-15"
},
{
product: "Ratón",
price: 30,
date: "2024-01-20"
}
],
preferences: { // Varias estructuras
theme: "dark",
notifications: true
}
}

2. Tipos de bases de datos NoSQL

1. Document DB (orientada a documentos)
└─ MongoDB, CouchDB
└─ Almacena documentos JSON

2. Key-Value DB (clave-valor)
└─ Redis, DynamoDB
└─ Caché rápido, almacenamiento de sesiones

3. Column-Family DB (orientada a columnas)
└─ Cassandra, HBase
└─ Análisis de datos a gran escala

4. Graph DB (grafo)
└─ Neo4j, Amazon Neptune
└─ Datos centrados en relaciones (redes sociales)

💡 Ejemplos prácticos

Ejemplo SQL (MySQL)

-- Crear tablas (esquema estricto)
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
age INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
product VARCHAR(100),
price DECIMAL(10, 2),
FOREIGN KEY (user_id) REFERENCES users(id)
);

-- Insertar datos
INSERT INTO users (name, email, age)
VALUES ('Juan', 'juan@mail.com', 25);

-- Obtener relaciones con JOIN
SELECT
users.name,
orders.product,
orders.price
FROM users
INNER JOIN orders ON users.id = orders.user_id
WHERE users.name = 'Juan';

-- Transacción (garantía ACID)
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

Ejemplo NoSQL (MongoDB)

// Sin esquema - estructura libre
db.users.insertOne({
name: "Juan",
email: "juan@mail.com",
age: 25,
orders: [
{ product: "Portátil", price: 1500 },
{ product: "Ratón", price: 30 }
]
});

// ¡Estructura diferente posible!
db.users.insertOne({
name: "María",
email: "maria@mail.com",
hobbies: ["lectura", "viajes"], // Campos diferentes
address: { // Objeto anidado
city: "Madrid",
zipcode: "28001"
}
});

// Búsqueda
db.users.find({ name: "Juan" });

// Búsqueda en documento anidado
db.users.find({
"orders.product": "Portátil"
});

// Actualización
db.users.updateOne(
{ name: "Juan" },
{
$set: { age: 26 },
$push: {
orders: { product: "Teclado", price: 80 }
}
}
);

// Agregación
db.users.aggregate([
{ $unwind: "$orders" },
{ $group: {
_id: "$name",
totalSpent: { $sum: "$orders.price" }
}
}
]);

SQL vs NoSQL en Node.js

// ============ SQL (MySQL) ============
const mysql = require('mysql2/promise');

const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'myapp'
});

// Obtener usuario con pedidos (JOIN necesario)
async function getUserWithOrders(userId) {
const [rows] = await pool.execute(`
SELECT
users.name,
users.email,
orders.product,
orders.price
FROM users
LEFT JOIN orders ON users.id = orders.user_id
WHERE users.id = ?
`, [userId]);

return rows;
}

// ============ NoSQL (MongoDB) ============
const { MongoClient } = require('mongodb');

const client = new MongoClient('mongodb://localhost:27017');
const db = client.db('myapp');
const users = db.collection('users');

// Obtener usuario con pedidos (JOIN no necesario - ya incluido)
async function getUserWithOrders(userId) {
const user = await users.findOne({ _id: userId });
// ¡La información de pedidos ya está en user.orders!
return user;
}

Ejemplo práctico: Sistema de blog

// ============ Enfoque SQL ============
// Estructura normalizada
/*
Tabla posts:
id, title, content, author_id, created_at

Tabla comments:
id, post_id, user_id, content, created_at

Tabla tags:
id, name

Tabla post_tags:
post_id, tag_id
*/

// Obtener publicación + comentarios + etiquetas → Varios JOIN necesarios
SELECT
posts.*,
comments.content as comment,
tags.name as tag
FROM posts
LEFT JOIN comments ON posts.id = comments.post_id
LEFT JOIN post_tags ON posts.id = post_tags.post_id
LEFT JOIN tags ON post_tags.tag_id = tags.id
WHERE posts.id = 1;

// ============ Enfoque NoSQL ============
// Estructura desnormalizada
{
_id: ObjectId("..."),
title: "Introducción a MongoDB",
content: "MongoDB es...",
author: {
id: "user123",
name: "Juan"
},
comments: [
{
user: { id: "user456", name: "María" },
content: "¡Excelente artículo!",
createdAt: "2024-01-15"
}
],
tags: ["base de datos", "NoSQL"],
createdAt: "2024-01-10"
}

// ¡Obtener todos los datos en una consulta!
db.posts.findOne({ _id: ObjectId("...") });

🤔 Preguntas frecuentes

P1. ¿Cuál debería elegir?

R: Elija según las características del proyecto:

✅ Elegir SQL en los siguientes casos:
├─ Estructura de datos clara y fija
├─ Relaciones complejas y muchos JOIN
├─ Transacciones ACID esenciales (finanzas, comercio electrónico)
├─ Integridad de datos importante
└─ Ej: Sistema bancario, software de contabilidad, ERP

✅ Elegir NoSQL en los siguientes casos:
├─ Estructura de datos fluida
├─ Lectura/escritura rápida importante
├─ Expansión horizontal (scale out) necesaria
├─ Procesamiento de datos de gran volumen
└─ Ej: Redes sociales, IoT, análisis en tiempo real, logs

P2. ¿Cuáles son las principales diferencias?

R:

CaracterísticaSQLNoSQL
Estructura de datosTablas (filas, columnas)Documentos, clave-valor, grafos, etc.
EsquemaFijo (estricto)Flexible (dinámico)
ExpansiónExpansión vertical (Scale Up)Expansión horizontal (Scale Out)
RelacionesConexión por JOINAnidamiento o referencia
TransacciónGarantía ACIDConsistencia eventual (BASE)
ConsultasLenguaje SQLDiferente para cada BD
EjemplosMySQL, PostgreSQLMongoDB, Redis
// SQL: ACID
Atomicity (Atomicidad): Todo o nada
Consistency (Consistencia): No viola reglas
Isolation (Aislamiento): Independencia entre transacciones
Durability (Durabilidad): Almacenamiento permanente

// NoSQL: BASE
Basically Available (Disponibilidad básica)
Soft state (Estado suave)
Eventually consistent (Consistencia eventual)

P3. ¿Diferencias de rendimiento?

R: Depende del patrón de uso:

// Ventaja SQL: Consultas complejas, JOIN
// Combinar datos de varias tablas
SELECT u.name, p.title, c.content
FROM users u
JOIN posts p ON u.id = p.author_id
JOIN comments c ON p.id = c.post_id
WHERE u.age > 20
ORDER BY p.created_at DESC;
// → Potente y preciso pero puede ser lento

// Ventaja NoSQL: Lectura/escritura rápida
// Toda la información en un documento
db.posts.find({ author_age: { $gt: 20 } })
.sort({ created_at: -1 });
// → Muy rápido pero JOIN complejos difíciles

// Ejemplo de benchmark
SQL: 10,000 lecturas/seg (JOIN complejos)
NoSQL: 100,000 lecturas/seg (búsqueda simple)

SQL: 5,000 escrituras/seg (garantía de transacción)
NoSQL: 50,000 escrituras/seg (escritura rápida)

P4. ¿Se pueden usar juntos?

R: ¡Sí! Se llama Persistencia Políglota:

// Ej: Sistema de comercio electrónico

// 1. SQL (MySQL) - Pedidos, pagos
// → Transacciones ACID esenciales
{
orders: "MySQL",
payments: "PostgreSQL",
inventory: "MySQL"
}

// 2. NoSQL (MongoDB) - Catálogo de productos
// → Atributos flexibles, búsqueda rápida
{
products: "MongoDB",
reviews: "MongoDB"
}

// 3. NoSQL (Redis) - Caché, sesiones
// → Lectura/escritura ultra rápida
{
cache: "Redis",
sessions: "Redis",
realtime: "Redis"
}

// 4. Graph DB (Neo4j) - Sistema de recomendaciones
// → Consultas basadas en relaciones
{
recommendations: "Neo4j",
socialGraph: "Neo4j"
}

P5. ¿Es difícil la migración?

R: Es posible con un enfoque estratégico:

// Estrategia de migración SQL → NoSQL

// 1. Enfoque híbrido
// - Nuevas funciones en NoSQL
// - Mantener funciones existentes en SQL

// 2. Migración progresiva
// Paso 1: Comenzar con datos de solo lectura
// Paso 2: Funciones menos críticas
// Paso 3: Funciones principales

// 3. Sincronización de datos
// - Captura de datos modificados (CDC)
// - Streaming de eventos (Kafka)

// Ej: Escritura dual
async function createUser(userData) {
// Escribir en SQL
const sqlUser = await mysqlDB.insert(userData);

// También escribir en NoSQL (asíncrono)
await mongooDB.insertOne({
...userData,
_id: sqlUser.id
}).catch(err => {
// SQL se mantiene incluso si falla
console.error('Fallo de sincronización MongoDB:', err);
});

return sqlUser;
}

🎓 Próximos pasos

Después de comprender SQL y NoSQL, aprenda:

  1. ¿Qué es una base de datos? - Conceptos básicos
  2. ¿Qué es Node.js? - Desarrollo backend
  3. ¿Qué es Docker? (documentación por venir) - Containerización de bases de datos

Puesta en práctica

# ============ Práctica MySQL ============
# Instalación
brew install mysql # macOS

# Ejecución
mysql -u root -p

# Crear tablas y consultas
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (id INT, name VARCHAR(50));
INSERT INTO users VALUES (1, 'Juan');
SELECT * FROM users;

# ============ Práctica MongoDB ============
# Instalación
brew tap mongodb/brew
brew install mongodb-community

# Ejecución
mongod --config /usr/local/etc/mongod.conf

# MongoDB Shell
mongosh

# Insertar y buscar datos
use testdb
db.users.insertOne({ name: "Juan", age: 25 })
db.users.find()

🎬 Resumen

SQL y NoSQL tienen cada uno sus ventajas y desventajas:

  • SQL: Datos estructurados, transacciones ACID, relaciones complejas
  • NoSQL: Esquema flexible, rendimiento rápido, expansión horizontal
  • Criterios de selección: Estructura de datos, escalabilidad, requisitos de consistencia
  • Políglota: Usar varias BD combinadas según necesidad

"No hay bala de plata" - ¡Elija la base de datos adecuada para su proyecto! ⚖️✨