Volver al inicio
Backend

Backend - Performance

Técnicas y conceptos fundamentales para optimizar el rendimiento de aplicaciones backend: Caching con Redis, Paginación e Índices en bases de datos

ConceptosBest Practices

Introducción

El rendimiento es crucial en aplicaciones backend. Estas técnicas te ayudarán a optimizar tus aplicaciones y mejorar la experiencia del usuario.

Caching con Redis

2 preguntas

1

¿Qué es caching y cuándo usar Redis?

Definición: Almacenar datos frecuentemente accedidos en memoria rápida para reducir tiempo de respuesta.
Redis: Sistema de almacenamiento en memoria (in-memory) tipo key-value.
Cuándo usar caching:
✓Datos que se leen frecuentemente pero cambian poco
✓Resultados de cálculos costosos
✓Consultas de base de datos complejas
✓Respuestas de APIs externas
✓Sesiones de usuario
Estrategias de caching:
EstrategiaDescripciónUso
Cache-Aside
App consulta cache, si no existe consulta DB
Más común, control total
Write-Through
Escribe en cache y DB simultáneamente
Consistencia garantizada
Write-Back
Escribe en cache primero, DB después
Alto rendimiento
Refresh-Ahead
Pre-carga datos antes de expirar
Datos siempre frescos
Ejemplo básico Redis:
javascript
// Guardar en cache
await redis.set('user:123', JSON.stringify(userData), 'EX', 3600); // Expira en 1 hora

// Leer de cache
const cached = await redis.get('user:123');
if (cached) {
  return JSON.parse(cached);
}
// Si no está en cache, consultar DB
2

¿Cuáles son las mejores prácticas para caching con Redis?

Estrategias de expiración:
✓TTL (Time To Live):
• Datos estáticos: TTL largo (24h-7d)
• Datos dinámicos: TTL corto (5-60 min)
• Datos críticos: Sin TTL + invalidación manual
✓Invalidación:
javascript
// Invalidar cuando se actualiza
await redis.del('user:123');

// Invalidar por patrón
await redis.keys('user:*').then(keys => redis.del(...keys));
Estructura de keys:
✓Usar nombres descriptivos: user:123:profile
✓Incluir versión: v1:user:123
✓Agrupar por namespace: cache:users:123
Consideraciones:
AspectoMejor Práctica
Memoria
Configurar maxmemory y política eviction
Serialización
JSON para objetos, strings para simples
Clustering
Redis Cluster para alta disponibilidad
Persistence
RDB + AOF según necesidades
Monitoring
Monitorear hit rate y memoria
Patrones comunes:
•Session Store: session:{sessionId}
•Rate Limiting: rate_limit:{ip}:{window}
•Leaderboards: Sorted Sets
•Pub/Sub: Para notificaciones en tiempo real

Paginación

2 preguntas

1

¿Qué es paginación y qué tipos existen?

Definición: Dividir grandes conjuntos de datos en páginas más pequeñas.
Tipos de paginación:
TipoCómo funciona✅ Ventajas❌ Desventajas
Offset-based
LIMIT 20 OFFSET 40
Simple, permite saltar páginas
Lento con offsets grandes
Cursor-based
WHERE id > last_id LIMIT 20
Rápido, consistente
No permite saltar páginas
Keyset
Similar a cursor pero con múltiples campos
Mejor para ordenamiento complejo
Más complejo
Offset-based (página tradicional):
sql
-- Página 3, 20 items por página
SELECT * FROM posts 
ORDER BY created_at DESC 
LIMIT 20 OFFSET 40;
Cursor-based (más eficiente):
sql
-- Usando cursor del último item visto
SELECT * FROM posts 
WHERE id > last_seen_id 
ORDER BY id ASC 
LIMIT 20;
Cuándo usar cada una:
✓Offset: Cuando necesitas permitir saltar páginas
✓Cursor: Para feeds infinitos, mejor rendimiento
✓Keyset: Ordenamiento complejo o múltiples campos
2

¿Cómo implementar paginación eficiente en APIs?

Estructura de respuesta API:
javascript
// Offset-based
{
  "data": [...],
  "pagination": {
    "page": 3,
    "perPage": 20,
    "total": 150,
    "totalPages": 8,
    "hasNext": true,
    "hasPrev": true
  }
}

// Cursor-based
{
  "data": [...],
  "pagination": {
    "nextCursor": "eyJpZCI6MTIzfQ",
    "hasNext": true
  }
}
Implementación eficiente:
javascript
// ✅ Usar índices en columnas de ordenamiento
CREATE INDEX idx_posts_created_at ON posts(created_at DESC);

// ✅ Evitar COUNT(*) en grandes tablas
// En lugar de contar todo, estimar o usar aproximación

// ✅ Cursor con múltiples campos
SELECT * FROM posts 
WHERE (created_at, id) > (last_created_at, last_id)
ORDER BY created_at DESC, id DESC
LIMIT 20;
Mejores prácticas:
✓Límite máximo de items por página (ej: 100)
✓Validar parámetros de paginación
✓Usar cursor para datasets grandes
✓Cachear primera página si es frecuente
✓Incluir metadata útil (total, hasNext, etc.)
Headers HTTP:
Link: <https://api.com/posts?page=2>; rel="next"
X-Total-Count: 150
X-Per-Page: 20

Índices en Bases de Datos

3 preguntas

1

¿Qué son los índices y cómo funcionan?

Definición: Estructura de datos que mejora la velocidad de búsqueda en tablas.
Cómo funcionan:
•Similar a índice de un libro
•Crea estructura ordenada de valores
•Permite búsqueda rápida sin escanear toda la tabla
•Trade-off: Más espacio, más lento en escrituras
Tipos de índices:
TipoDescripciónCuándo usar
B-Tree
Estándar, balanceado
Mayoría de casos (default)
Hash
Lookup O(1)
Igualdad exacta, no rangos
Bitmap
Para columnas con pocos valores únicos
Columnas booleanas, estados
Full-Text
Búsqueda de texto completo
Búsquedas en texto largo
Composite
Múltiples columnas
Consultas con múltiples WHERE
Ejemplo:
sql
-- Crear índice simple
CREATE INDEX idx_users_email ON users(email);

-- Consulta rápida (usa índice)
SELECT * FROM users WHERE email = 'user@example.com';

-- Consulta lenta (sin índice, full table scan)
SELECT * FROM users WHERE name = 'Juan';
Impacto en rendimiento:
•Sin índice: O(n) - escanea toda la tabla
•Con índice: O(log n) - búsqueda binaria
•Diferencia: De segundos a milisegundos en tablas grandes
2

¿Cuándo crear índices y cuáles son las mejores prácticas?

Cuándo crear índices:
✓Columnas en WHERE frecuentemente:
sql
WHERE user_id = ? -- Crear índice en user_id
  WHERE status = 'active' -- Si hay muchos valores únicos
✓Columnas en JOIN:
sql
JOIN orders ON orders.user_id = users.id
  -- Índice en orders.user_id
✓Columnas en ORDER BY:
sql
ORDER BY created_at DESC
  -- Índice en created_at
✓Columnas en GROUP BY:
sql
GROUP BY category_id
  -- Índice en category_id
Cuándo NO crear índices:
✗ Tablas pequeñas (< 1000 filas)
✗ Columnas que cambian frecuentemente
✗ Columnas con pocos valores únicos (ej: género)
✗ Columnas raramente usadas en consultas
Mejores prácticas:
✓Índices compuestos:
sql
-- Ordenar columnas por selectividad (más selectiva primero)
  CREATE INDEX idx_orders_user_status 
  ON orders(user_id, status, created_at);
  
  -- Útil para: WHERE user_id = ? AND status = ? ORDER BY created_at
✓Covering Index:
sql
-- Incluir columnas usadas en SELECT
  CREATE INDEX idx_users_email_name 
  ON users(email) INCLUDE (name, avatar);
✓Monitorear uso:
• Revisar índices no usados
• Eliminar índices redundantes
• Analizar query plans
Trade-offs:
•Espacio: Índices ocupan espacio adicional
•Escritura: INSERT/UPDATE/DELETE más lentos
•Mantenimiento: Índices necesitan mantenimiento
•Balance: No crear demasiados índices
3

¿Cómo analizar y optimizar índices?

Herramientas de análisis:
PostgreSQL:
sql
-- Ver índices de una tabla
\d table_name

-- Analizar query plan
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';

-- Ver índices no usados
SELECT * FROM pg_stat_user_indexes WHERE idx_scan = 0;
MySQL:
sql
-- Ver índices
SHOW INDEX FROM table_name;

-- Analizar query
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';

-- Ver estadísticas
SHOW TABLE STATUS LIKE 'table_name';
Métricas importantes:
MétricaQué indica
Index Scan vs Seq Scan
Si usa índice o escanea tabla completa
Index Selectivity
Porcentaje de filas que el índice filtra
Index Usage
Cuántas veces se usa el índice
Index Size
Espacio ocupado
Optimización:
✓Rebuild índices:
sql
-- PostgreSQL
  REINDEX INDEX idx_users_email;
  
  -- MySQL
  ALTER TABLE users DROP INDEX idx_email;
  ALTER TABLE users ADD INDEX idx_email(email);
✓Actualizar estadísticas:
sql
-- PostgreSQL
  ANALYZE table_name;
  
  -- MySQL
  ANALYZE TABLE table_name;
✓Índices parciales:
sql
-- Solo indexar filas activas
  CREATE INDEX idx_active_users 
  ON users(email) WHERE status = 'active';
Señales de problemas:
•Consultas lentas en tablas grandes
•Full table scans frecuentes
•Índices no usados ocupando espacio
•Escrituras muy lentas (demasiados índices)