Diagnóstico de consultas lentas · Plan de índices · Queries optimizadas · Dashboard de monitoring
-- EXPLAIN ANALYZE output (antes de optimizar) EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT * FROM leads JOIN deals ON leads.id = deals.lead_id JOIN stages ON deals.stage_id = stages.id WHERE LOWER(leads.email) LIKE '%@empresa.com%' AND deals.created_at > '2024-01-01' ORDER BY deals.value DESC; -- Resultado del plan: -- Sort (cost=24831.44..24856.44 rows=10000) (actual time=9187.33..9193.41 rows=8723) -- Sort Key: deals.value DESC -- -> Hash Join (cost=2148.50..23981.44) (actual time=145.82..9024.11 rows=8723) -- -> Seq Scan on deals (cost=0.00..18234.00) ⚠️ FULL TABLE SCAN -- Filter: (created_at > '2024-01-01'::date) -- Rows Removed by Filter: 34219 -- -> Hash (cost=1834.00..1834.00) -- -> Seq Scan on leads (cost=0.00..1834.00) ⚠️ FULL TABLE SCAN -- Filter: (lower(email) ~~ '%@empresa.com%') -- Rows Removed by Filter: 172341 -- Planning Time: 12.43 ms -- Execution Time: 9187.33 ms ← 9.2 segundos!
SELECT LEFT(query, 80) AS query_preview, calls, ROUND(total_exec_time::NUMERIC, 2) AS total_ms, ROUND(mean_exec_time::NUMERIC, 2) AS mean_ms, ROUND(stddev_exec_time::NUMERIC, 2) AS stddev_ms, rows FROM pg_stat_statements WHERE calls > 100 ORDER BY mean_exec_time DESC LIMIT 10;
SELECT schemaname, tablename, seq_scan, seq_tup_read, idx_scan, ROUND( seq_tup_read::FLOAT / NULLIF(seq_scan, 0) ) AS avg_rows_per_scan FROM pg_stat_user_tables WHERE seq_scan > 50 AND schemaname = 'public' ORDER BY seq_tup_read DESC LIMIT 10;
SELECT schemaname, tablename, indexname, idx_scan, pg_size_pretty( pg_relation_size(indexrelid) ) AS index_size FROM pg_stat_user_indexes WHERE idx_scan = 0 AND schemaname = 'public' ORDER BY pg_relation_size(indexrelid) DESC;
-- Actualizar estadísticas tras bulk imports ANALYZE VERBOSE events; ANALYZE VERBOSE leads; ANALYZE VERBOSE deals; -- Vacuum + análisis (sin bloquear tabla) VACUUM ANALYZE events; -- Verificar uso de índices nuevos (24h post-deploy) SELECT indexname, idx_scan, idx_tup_read FROM pg_stat_user_indexes WHERE tablename IN ('events', 'leads', 'deals') ORDER BY idx_scan DESC;