postgresql-performance-expert

Optimizacion de PostgreSQL para Senior Full-Stack Developer. Usar cuando el usuario necesite diagnosticar queries lentos, optimizar performance de base de datos, disenar indices, resolver N+1 queries, o defender experiencia en optimizacion. Activa con palabras como PostgreSQL, query lento, performance, EXPLAIN, indice, N+1, optimizar base de datos, latencia. Especializado en aplicaciones SaaS con Node.js.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "postgresql-performance-expert" with this command: npx skills add founderjourney/claude-skills/founderjourney-claude-skills-postgresql-performance-expert

PostgreSQL Performance Expert

Sistema para diagnosticar y resolver problemas de performance en PostgreSQL.

Workflow de Diagnostico

1. Identificar el problema

SINTOMAS:
- Endpoint lento (>500ms)
- Timeouts en queries
- CPU/memoria alta en DB
- Conexiones agotadas

HERRAMIENTAS:
- EXPLAIN ANALYZE
- pg_stat_statements
- slow query log
- connection pool metrics

2. Proceso de optimizacion

1. MEDIR     → EXPLAIN ANALYZE con query real
2. IDENTIFICAR → Seq Scan? Nested Loop? Alto cost?
3. HIPOTESIS  → Falta indice? N+1? Over-fetching?
4. APLICAR    → Crear indice / reescribir query
5. VERIFICAR  → Re-ejecutar EXPLAIN, comparar
6. MONITOREAR → Observar en produccion

EXPLAIN ANALYZE: Como Leerlo

Ejecutar correctamente

-- Siempre con ANALYZE para tiempos reales
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT * FROM reservations
WHERE property_id = 123
  AND check_in >= '2024-01-01';

Que buscar

MALO - Seq Scan en tabla grande:
Seq Scan on reservations  (cost=0.00..15432.00 rows=50000)
  Filter: (property_id = 123)
  Rows Removed by Filter: 49000
→ Solucion: agregar indice en property_id

MALO - Nested Loop con muchas filas:
Nested Loop  (cost=0.00..125000.00 rows=1000)
  -> Seq Scan on properties
  -> Index Scan on reservations (1000 loops)
→ Solucion: cambiar a Hash Join o agregar indice

BUENO - Index Scan:
Index Scan using idx_reservations_property
  Index Cond: (property_id = 123)
→ Usando indice correctamente

Problemas Comunes + Soluciones

N+1 Queries

// MALO: N+1
const properties = await db('properties').select('*');
for (const prop of properties) {
  prop.reservations = await db('reservations')
    .where({ property_id: prop.id }); // N queries!
}

// BUENO: Eager loading
const properties = await db('properties')
  .select('properties.*')
  .leftJoin('reservations', 'properties.id', 'reservations.property_id');

// O con subquery
const properties = await db('properties').select('*');
const propIds = properties.map(p => p.id);
const reservations = await db('reservations')
  .whereIn('property_id', propIds);
// Agrupar en memoria

Missing Index

-- Query lento
SELECT * FROM orders
WHERE user_id = 123 AND status = 'pending'
ORDER BY created_at DESC;

-- Agregar indice compuesto
CREATE INDEX idx_orders_user_status_created
ON orders (user_id, status, created_at DESC);

-- Verificar uso
EXPLAIN ANALYZE SELECT ...
-- Deberia mostrar Index Scan

Over-fetching

// MALO: traer todo
const users = await db('users').select('*');

// BUENO: solo lo necesario
const users = await db('users').select('id', 'name', 'email');

// MALO: sin limite
const logs = await db('audit_logs').where({ user_id: 123 });

// BUENO: con limite
const logs = await db('audit_logs')
  .where({ user_id: 123 })
  .orderBy('created_at', 'desc')
  .limit(100);

Indices: Guia Rapida

Tipos

B-tree (default): =, <, >, BETWEEN, ORDER BY
  CREATE INDEX idx_name ON table (column);

GIN: arrays, JSONB, full-text search
  CREATE INDEX idx_tags ON posts USING GIN (tags);

Partial: solo subset de filas
  CREATE INDEX idx_active ON users (email) WHERE active = true;

Covering: incluir columnas extra
  CREATE INDEX idx_orders ON orders (user_id) INCLUDE (total, status);

Indice Compuesto: Orden Importa

-- Indice en (A, B, C)
CREATE INDEX idx ON table (a, b, c);

-- Funciona para:
WHERE a = 1
WHERE a = 1 AND b = 2
WHERE a = 1 AND b = 2 AND c = 3
WHERE a = 1 ORDER BY b

-- NO funciona para:
WHERE b = 2  -- Necesita A primero
WHERE c = 3  -- Necesita A y B primero

Connection Pooling

// Sin pooling: nueva conexion por query (lento, inseguro)
// Con pooling: reusar conexiones

// Knex.js config
const db = knex({
  client: 'pg',
  connection: {
    host: process.env.DB_HOST,
    database: process.env.DB_NAME,
    // ...
  },
  pool: {
    min: 2,        // Conexiones minimas
    max: 10,       // Conexiones maximas
    acquireTimeoutMillis: 30000,
    idleTimeoutMillis: 30000
  }
});

// Monitorear pool
setInterval(() => {
  const pool = db.client.pool;
  console.log({
    used: pool.numUsed(),
    free: pool.numFree(),
    pending: pool.numPendingAcquires()
  });
}, 60000);

Tu Experiencia: Script de Respuesta

"En HostelOS tuve un endpoint que tardaba 800ms. Esto es lo que hice:

1. MEDIR
   EXPLAIN ANALYZE mostro Seq Scan en tabla de 50K reservas

2. IDENTIFICAR
   Query filtraba por property_id y rango de fechas, pero
   no habia indice para esa combinacion

3. APLICAR
   CREATE INDEX idx_reservations_property_dates
   ON reservations (property_id, check_in, check_out);

4. RESULTADO
   Bajo a 50ms (94% mejora)

5. SIGUIENTE PROBLEMA
   Con mas datos, subio a 120ms. Agregue partial index:
   CREATE INDEX idx_active_reservations
   ON reservations (property_id, check_in)
   WHERE status = 'confirmed';

   Bajo a 35ms."

Checklist de Performance

INDICES
[ ] Queries frecuentes tienen indices apropiados
[ ] Indices compuestos en orden correcto
[ ] Partial indices para subsets comunes
[ ] No hay indices duplicados o sin usar

QUERIES
[ ] Sin N+1 (usar eager loading)
[ ] SELECT solo columnas necesarias
[ ] LIMIT en queries grandes
[ ] Paginacion con cursor, no OFFSET

CONFIGURACION
[ ] Connection pooling configurado
[ ] shared_buffers apropiado (~25% RAM)
[ ] work_mem para queries complejas
[ ] Statement timeout configurado

MONITOREO
[ ] slow_query_log habilitado
[ ] pg_stat_statements instalado
[ ] Alertas para queries >1s
[ ] Dashboard de metricas DB

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

yc-sv-development-framework

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

code-review-senior-perspective

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

claude-code-guide

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

devops-pathfinders

No summary provided by upstream source.

Repository SourceNeeds Review