Debate para devs 💬: ¿Cuál es el futuro de las bases de datos?

17 de noviembre de 2024
9 min lectura
By Sly & AI

Tabla de Contenidos

Secciones de esta publicación.
Haz clic en cualquiera de ellas para ir directamente a esa sección.

Las bases de datos están cambiando más rápido que nunca. Hace cinco años elegías entre MySQL y PostgreSQL, tal vez MongoDB si querías parecer cool. Hoy tienes que decidir entre SQL tradicional, NoSQL, NewSQL, bases de datos vectoriales, soluciones serverless, edge databases, y opciones que ni siquiera existían el año pasado.

¿Hacia dónde vamos? Vamos a explorar las tendencias actuales con código real y opiniones sin filtro.

El Estado Actual: Demasiadas Opciones

Categorías principales que existen hoy:

  1. SQL Tradicional: PostgreSQL, MySQL, SQL Server
  2. NoSQL: MongoDB, CouchDB, Cassandra
  3. NewSQL: CockroachDB, TiDB, YugabyteDB
  4. Serverless: PlanetScale, Neon, Supabase
  5. Edge: Turso, Cloudflare D1, Fly.io
  6. Vectoriales: Pinecone, Weaviate, Qdrant
  7. Híbridas: SurrealDB, EdgeDB

Esto es insostenible. Nadie puede conocer todas. Así que vamos a enfocarnos en lo que realmente importa.

Tendencia 1: SQL No Va a Morir (Lo Siento, MongoDB)

PostgreSQL está teniendo un renacimiento. Y hay razones concretas:

-- PostgreSQL ahora hace cosas que antes requerían MongoDB
CREATE TABLE productos (
  id SERIAL PRIMARY KEY,
  nombre TEXT,
  especificaciones JSONB,
  vector_embedding vector(1536)
);
 
-- Búsqueda en JSON como en MongoDB
SELECT * FROM productos 
WHERE especificaciones @> '{"color": "rojo"}';
 
-- Búsqueda vectorial para IA
SELECT * FROM productos 
ORDER BY vector_embedding <-> '[0.1, 0.2, ...]'
LIMIT 10;
 
-- Full-text search
SELECT * FROM productos 
WHERE to_tsvector('spanish', nombre) @@ to_tsquery('laptop');

Una base de datos. Cuatro casos de uso que antes requerían sistemas diferentes.

Postgres en la Práctica

// Con Prisma (el ORM que no apesta)
import { PrismaClient } from '@prisma/client'
 
const prisma = new PrismaClient()
 
// Queries type-safe
async function buscarProductos(filtros) {
  return await prisma.producto.findMany({
    where: {
      especificaciones: {
        path: ['color'],
        equals: filtros.color
      },
      precio: {
        lte: filtros.precioMax
      }
    },
    include: {
      reviews: {
        orderBy: { fecha: 'desc' },
        take: 5
      }
    }
  })
}
 
// La magia: TypeScript sabe exactamente qué devuelve esto
const productos = await buscarProductos({ 
  color: 'rojo', 
  precioMax: 1000 
})

Por qué Postgres gana:

  • ACID real, no “eventual consistency”
  • Extensiones para todo (PostGIS, pgvector, TimescaleDB)
  • Rendimiento probado en producción durante décadas
  • No pagas extra por features básicas

Tendencia 2: Serverless Está Cambiando Todo

El problema tradicional de las bases de datos:

// Código viejo con pool de conexiones
import mysql from 'mysql2/promise'
 
const pool = mysql.createPool({
  host: 'db.example.com',
  user: 'app',
  password: 'secret',
  connectionLimit: 10, // ¿10? ¿20? ¿Quién sabe?
  waitForConnections: true,
  queueLimit: 0
})
 
// En serverless esto es un desastre
// Cada invocación crea conexiones nuevas
// Lambda tiene 1000 instancias = 10,000 conexiones
// Tu DB: 💀

Enter: Neon y PlanetScale

// Neon Serverless Postgres
import { neon } from '@neondatabase/serverless'
 
// HTTP-based, sin pool de conexiones
const sql = neon(process.env.DATABASE_URL)
 
export default async function handler(req) {
  // Cada query es HTTP, escala infinitamente
  const users = await sql`
    SELECT * FROM users 
    WHERE email = ${req.body.email}
  `
  
  return Response.json(users)
}

Ventajas reales:

  • Zero cold starts
  • Pagas por query, no por tiempo
  • Escala automático
  • No más “too many connections”

Costo real: ~20/mes para un proyecto pequeño vs 15/mes de un VPS tradicional. La diferencia no es tanta.

Tendencia 3: Edge Computing Requiere Edge Databases

Tu app está en el edge (Cloudflare Workers, Vercel Edge). Tu base de datos en Virginia, USA. Latencia: 200ms. Inaceptable.

Turso (SQLite Distribuido)

import { createClient } from '@libsql/client'
 
const db = createClient({
  url: 'libsql://your-db.turso.io',
  authToken: process.env.TURSO_TOKEN
})
 
// Esto corre en el edge, cerca del usuario
export default async function handler(req) {
  const result = await db.execute({
    sql: 'SELECT * FROM posts WHERE slug = ?',
    args: [req.params.slug]
  })
  
  // Latencia: <10ms desde cualquier parte del mundo
  return new Response(JSON.stringify(result))
}

La magia: Turso replica tu SQLite a múltiples regiones. Writes van al primary, reads son locales.

Cloudflare D1

// Dentro de un Cloudflare Worker
export default {
  async fetch(request, env) {
    const { results } = await env.DB.prepare(
      'SELECT * FROM products WHERE category = ?'
    ).bind('electronics').all()
    
    return Response.json(results)
  }
}

Limitación actual: D1 aún está en beta y tiene límites estrictos. Pero la dirección es clara.

Tendencia 4: Bases de Datos Vectoriales para IA

Si tu app usa IA (y debería), necesitas almacenar embeddings. Postgres puede, pero las DBs especializadas lo hacen mejor.

Pinecone para RAG

import { PineconeClient } from '@pinecone-database/pinecone'
import OpenAI from 'openai'
 
const pinecone = new PineconeClient()
await pinecone.init({
  apiKey: process.env.PINECONE_API_KEY,
  environment: 'us-west1-gcp'
})
 
const openai = new OpenAI()
 
// 1. Crear embeddings de tu documentación
async function indexarDocs(documentos) {
  const index = pinecone.Index('docs')
  
  for (const doc of documentos) {
    const embedding = await openai.embeddings.create({
      model: 'text-embedding-3-small',
      input: doc.contenido
    })
    
    await index.upsert([{
      id: doc.id,
      values: embedding.data[0].embedding,
      metadata: { texto: doc.contenido }
    }])
  }
}
 
// 2. Buscar contexto relevante
async function buscarContexto(pregunta) {
  const index = pinecone.Index('docs')
  
  const questionEmbedding = await openai.embeddings.create({
    model: 'text-embedding-3-small',
    input: pregunta
  })
  
  const results = await index.query({
    vector: questionEmbedding.data[0].embedding,
    topK: 5,
    includeMetadata: true
  })
  
  return results.matches.map(m => m.metadata.texto)
}
 
// 3. Usar en un chatbot
async function responderPregunta(pregunta) {
  const contexto = await buscarContexto(pregunta)
  
  const respuesta = await openai.chat.completions.create({
    model: 'gpt-4-turbo',
    messages: [
      {
        role: 'system',
        content: `Responde basándote en este contexto: ${contexto.join('\n')}`
      },
      { role: 'user', content: pregunta }
    ]
  })
  
  return respuesta.choices[0].message.content
}

Alternativa open source: Qdrant

import { QdrantClient } from '@qdrant/js-client-rest'
 
const client = new QdrantClient({ url: 'http://localhost:6333' })
 
// Mismo concepto, self-hosted, gratis
await client.upsert('docs', {
  points: [
    {
      id: 1,
      vector: [0.1, 0.2, 0.3, ...],
      payload: { texto: 'contenido del doc' }
    }
  ]
})

Tendencia 5: Multi-Model Databases (Todo en Una)

SurrealDB quiere ser la última base de datos que necesites:

import Surreal from 'surrealdb.js'
 
const db = new Surreal('http://localhost:8000/rpc')
await db.signin({ user: 'root', pass: 'root' })
await db.use('test', 'test')
 
// SQL-like pero con superpoderes
await db.query(`
  CREATE user SET 
    name = 'John',
    friends = [(SELECT * FROM user WHERE age > 25)],
    location = { 
      type: 'Point', 
      coordinates: [-0.118092, 51.509865] 
    };
`)
 
// Graph queries
const result = await db.query(`
  SELECT *, ->friends->user.* FROM user
`)
 
// Realtime subscriptions
const users = db.live('user')
for await (const action of users) {
  console.log('User changed:', action)
}

Problema: ¿Es mejor ser bueno en todo o excelente en una cosa? El jurado aún delibera.

La Realidad: Stack Híbrido es el Futuro

No vas a usar una sola base de datos. Así funciona un stack moderno:

// 1. PostgreSQL para datos transaccionales
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
 
// 2. Redis para cache y rate limiting
import { Redis } from '@upstash/redis'
const redis = new Redis({ url: process.env.REDIS_URL })
 
// 3. Pinecone para embeddings y búsqueda semántica
import { PineconeClient } from '@pinecone-database/pinecone'
const pinecone = new PineconeClient()
 
// 4. Cloudflare KV para edge caching
// (en Workers)
const cachedData = await env.KV.get('key')
 
// Ejemplo real: Endpoint de búsqueda optimizado
export async function buscar(query, userId) {
  // 1. Check rate limit (Redis)
  const remaining = await redis.decr(`rate:${userId}`)
  if (remaining < 0) throw new Error('Rate limited')
  
  // 2. Check cache (Cloudflare KV en edge)
  const cached = await env.KV.get(`search:${query}`)
  if (cached) return JSON.parse(cached)
  
  // 3. Búsqueda semántica (Pinecone)
  const embedding = await getEmbedding(query)
  const similar = await pinecone.query({ vector: embedding })
  
  // 4. Fetch data completa (PostgreSQL)
  const results = await prisma.product.findMany({
    where: { id: { in: similar.map(s => s.id) } }
  })
  
  // 5. Cache result
  await env.KV.put(`search:${query}`, JSON.stringify(results), {
    expirationTtl: 3600
  })
  
  return results
}

Cuatro bases de datos diferentes. Cada una haciendo lo que hace mejor.

Predicciones Controversiales

1. MongoDB Va a Perder Terreno

Postgres con JSONB hace el 90% de lo que MongoDB hace, pero con ACID y mejor ecosistema. MongoDB se queda con casos de uso muy específicos.

2. MySQL Se Va a Quedar Atrás

PostgreSQL es objetivamente superior en features. La única razón para elegir MySQL hoy es legacy o por WordPress.

3. Serverless Se Vuelve el Default

En 3 años, deployar una DB tradicional será visto como “hacer las cosas a la antigua”. Neon, PlanetScale y similares serán el estándar.

4. Graph Databases Siguen Siendo Nicho

Neo4j prometió revolucionar todo. No pasó. Los use cases reales de graph DBs son limitados. SQL con recursive CTEs resuelve el 80% de casos.

-- Postgres puede hacer queries de grafos
WITH RECURSIVE friends AS (
  SELECT id, name FROM users WHERE id = 1
  UNION
  SELECT u.id, u.name 
  FROM users u
  JOIN friendships f ON u.id = f.friend_id
  JOIN friends fr ON f.user_id = fr.id
)
SELECT * FROM friends;

5. Local-First con Sync Automático

Aplicaciones que funcionan offline y sincronizan cuando hay conexión. PowerSync, Electric SQL y similares están resolviendo esto:

import { PowerSyncDatabase } from '@powersync/web'
 
const db = new PowerSyncDatabase({
  schema: mySchema,
  database: { dbFilename: 'app.db' }
})
 
// Funciona offline
await db.execute('INSERT INTO todos (text) VALUES (?)', ['Comprar leche'])
 
// Sync automático cuando hay conexión
await db.connect({
  powerSyncUrl: 'https://myapp.powersync.com',
  token: userToken
})

Lo Que Deberías Usar Hoy

Para un nuevo proyecto SaaS:

// Stack recomendado 2024
const stack = {
  primary: 'Neon PostgreSQL',        // Datos transaccionales
  cache: 'Upstash Redis',            // Cache + rate limiting  
  search: 'Meilisearch',             // Full-text search
  ai: 'pgvector en Postgres',        // Embeddings (empieza simple)
  analytics: 'Tinybird',             // ClickHouse managed
  fileStorage: 'Cloudflare R2'       // S3-compatible, más barato
}

Código de setup:

// lib/db.ts
import { PrismaClient } from '@prisma/client'
import { Redis } from '@upstash/redis'
 
export const prisma = new PrismaClient()
export const redis = Redis.fromEnv()
 
// Helper para cache con Redis
export async function cached<T>(
  key: string,
  fetcher: () => Promise<T>,
  ttl: number = 3600
): Promise<T> {
  const cached = await redis.get(key)
  if (cached) return cached as T
  
  const fresh = await fetcher()
  await redis.setex(key, ttl, JSON.stringify(fresh))
  return fresh
}
 
// Uso
const users = await cached(
  'users:active',
  () => prisma.user.findMany({ where: { active: true } }),
  300 // 5 minutos
)

Aquí No Hay Bala de Plata

El futuro de las bases de datos no es una tecnología que las reemplace a todas. Es usar la herramienta correcta para cada problema:

  • Postgres: Tu base principal. Confiable, potente, gratis.
  • Redis: Cache y pub/sub. Rápido y simple.
  • Vector DB: Solo si haces IA en serio.
  • Edge DB: Para latencia crítica.

Empieza con Postgres. Agrega complejidad solo cuando la necesites. La mayoría de apps nunca necesitan más que Postgres + Redis.

Y recuerda: la mejor base de datos es la que conoces bien. No cambies solo porque hay algo nuevo y brillante. Cambia cuando tengas un problema que tu stack actual no puede resolver.

El futuro ya está aquí. Solo está distribuido de manera desigual.