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:
| Estrategia | Descripción | Uso |
|---|---|---|
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 DB2
¿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:123Consideraciones:
| Aspecto | Mejor 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:
| Tipo | Có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:
| Tipo | Descripción | Cuá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_idCuá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étrica | Qué 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)