191 lines
7.8 KiB
SQL
191 lines
7.8 KiB
SQL
-- =====================================================================
|
|
-- FASE 1: Índices Críticos para Optimización Inmediata
|
|
-- Propósito: Mejorar rendimiento de scanning_report_daily_full
|
|
-- Tiempo estimado: 1-2 horas (dependiendo del tamaño de datos)
|
|
-- Mejora esperada: 40-60% más rápido
|
|
-- =====================================================================
|
|
|
|
-- IMPORTANTE: Todos los índices usan CONCURRENTLY para no bloquear producción
|
|
-- Esto permite crear índices sin downtime, pero toma más tiempo
|
|
|
|
SET statement_timeout = 0;
|
|
SET lock_timeout = 0;
|
|
|
|
-- =====================================================================
|
|
-- 1. Índice para JOIN de SplashUserConnections
|
|
-- =====================================================================
|
|
-- Problema: El LEFT JOIN con DISTINCT es muy lento
|
|
-- Solución: Índice filtrado solo en registros no eliminados
|
|
|
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_splash_user_connections_mac_notdeleted
|
|
ON "SplashUserConnections" ("MacAddress")
|
|
WHERE "IsDeleted" = false;
|
|
|
|
COMMENT ON INDEX idx_splash_user_connections_mac_notdeleted IS
|
|
'Índice parcial para JOIN rápido en scanning_report_daily_full. Solo indexa registros activos.';
|
|
|
|
-- =====================================================================
|
|
-- 2. Índice compuesto principal para queries comunes
|
|
-- =====================================================================
|
|
-- Optimiza: WHERE NetworkId IN (...) AND DetectionDate BETWEEN ... AND ...
|
|
-- Este es el patrón más común en los dashboards
|
|
|
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_scanning_report_network_date_person
|
|
ON scanning_report_daily_full ("NetworkId", "DetectionDate" DESC, "PersonType")
|
|
INCLUDE ("MacAddress", "DurationInMinutes", "IsRegisteredUser", "DetectionsCount");
|
|
|
|
COMMENT ON INDEX idx_scanning_report_network_date_person IS
|
|
'Índice compuesto para filtros por red + fecha + tipo. INCLUDE permite index-only scans.';
|
|
|
|
-- =====================================================================
|
|
-- 3. Índice para filtros de rango de fechas
|
|
-- =====================================================================
|
|
-- Optimiza: WHERE DetectionDate BETWEEN ... AND ...
|
|
-- Útil para queries de métricas sin filtro de red
|
|
|
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_scanning_report_detection_date_network
|
|
ON scanning_report_daily_full ("DetectionDate" DESC, "NetworkId");
|
|
|
|
COMMENT ON INDEX idx_scanning_report_detection_date_network IS
|
|
'Índice para queries de rango de fechas. Orden DESC optimiza ORDER BY recientes.';
|
|
|
|
-- =====================================================================
|
|
-- 4. Índice para filtros por tipo de persona (PasserBy/Visitor)
|
|
-- =====================================================================
|
|
-- Optimiza: WHERE PersonType = 'Visitor'
|
|
-- Usado en análisis de conversión
|
|
|
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_scanning_report_person_type
|
|
ON scanning_report_daily_full ("PersonType")
|
|
WHERE "PersonType" IS NOT NULL;
|
|
|
|
COMMENT ON INDEX idx_scanning_report_person_type IS
|
|
'Índice filtrado para análisis por tipo de persona (Visitor/PasserBy).';
|
|
|
|
-- =====================================================================
|
|
-- 5. Índice para búsquedas por MAC Address
|
|
-- =====================================================================
|
|
-- Optimiza: WHERE MacAddress = '...'
|
|
-- Usado en reportes individuales y seguimiento de dispositivos
|
|
|
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_scanning_report_mac_address
|
|
ON scanning_report_daily_full ("MacAddress");
|
|
|
|
COMMENT ON INDEX idx_scanning_report_mac_address IS
|
|
'Índice para búsquedas por dispositivo específico (MAC address).';
|
|
|
|
-- =====================================================================
|
|
-- 6. Índice para análisis por Access Point
|
|
-- =====================================================================
|
|
-- Optimiza: JOIN con SplashAccessPoints
|
|
-- Mejora queries de distribución por ubicación
|
|
|
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_splash_access_points_mac
|
|
ON "SplashAccessPoints" ("Mac")
|
|
WHERE "IsDeleted" = false;
|
|
|
|
COMMENT ON INDEX idx_splash_access_points_mac IS
|
|
'Índice para JOIN rápido con AccessPoints en scanning reports.';
|
|
|
|
-- =====================================================================
|
|
-- 7. Índice para JOIN con Networks
|
|
-- =====================================================================
|
|
-- Optimiza: LEFT JOIN "SplashMerakiNetworks"
|
|
-- Mejora enriquecimiento de datos
|
|
|
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_splash_networks_id_org
|
|
ON "SplashMerakiNetworks" ("Id", "OrganizationId")
|
|
WHERE "IsDeleted" = false;
|
|
|
|
COMMENT ON INDEX idx_splash_networks_id_org IS
|
|
'Índice para JOINs de Networks con Organizations en scanning reports.';
|
|
|
|
-- =====================================================================
|
|
-- 8. Índice compuesto para widget "Comparativa entre Sucursales"
|
|
-- =====================================================================
|
|
-- Optimiza la query específica del widget más lento
|
|
|
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_scanning_report_branch_comparison
|
|
ON scanning_report_daily_full ("NetworkId", "DetectionDate" DESC, "PersonType", "IsRegisteredUser")
|
|
WHERE "DurationInMinutes" > 1;
|
|
|
|
COMMENT ON INDEX idx_scanning_report_branch_comparison IS
|
|
'Índice especializado para widget Comparativa entre Sucursales. Filtrado por duración > 1min.';
|
|
|
|
-- =====================================================================
|
|
-- 9. Actualizar estadísticas del optimizador
|
|
-- =====================================================================
|
|
-- Crítico: PostgreSQL necesita estadísticas actualizadas para elegir el índice correcto
|
|
|
|
ANALYZE "SplashUserConnections";
|
|
ANALYZE "SplashAccessPoints";
|
|
ANALYZE "SplashMerakiNetworks";
|
|
ANALYZE "SplashMerakiOrganizations";
|
|
|
|
-- Si scanning_report_daily_full es materialized view:
|
|
-- ANALYZE scanning_report_daily_full;
|
|
|
|
-- Si es vista regular, analizar la tabla base:
|
|
-- ANALYZE "SplashWiFiScanningData";
|
|
|
|
-- =====================================================================
|
|
-- 10. Verificar que los índices se crearon correctamente
|
|
-- =====================================================================
|
|
SELECT
|
|
schemaname,
|
|
tablename,
|
|
indexname,
|
|
indexdef
|
|
FROM pg_indexes
|
|
WHERE indexname LIKE 'idx_scanning%' OR indexname LIKE 'idx_splash%'
|
|
ORDER BY tablename, indexname;
|
|
|
|
-- =====================================================================
|
|
-- 11. Verificar tamaño de índices
|
|
-- =====================================================================
|
|
SELECT
|
|
schemaname,
|
|
tablename,
|
|
indexname,
|
|
pg_size_pretty(pg_relation_size(schemaname||'.'||indexname)) as index_size
|
|
FROM pg_indexes
|
|
WHERE indexname LIKE 'idx_scanning%' OR indexname LIKE 'idx_splash%'
|
|
ORDER BY pg_relation_size(schemaname||'.'||indexname) DESC;
|
|
|
|
-- =====================================================================
|
|
-- 12. Monitoreo: Queries lentas relacionadas (requiere pg_stat_statements)
|
|
-- =====================================================================
|
|
-- Descomentar si pg_stat_statements está habilitado:
|
|
|
|
/*
|
|
SELECT
|
|
query,
|
|
calls,
|
|
mean_exec_time,
|
|
max_exec_time,
|
|
total_exec_time
|
|
FROM pg_stat_statements
|
|
WHERE query ILIKE '%scanning_report_daily_full%'
|
|
ORDER BY mean_exec_time DESC
|
|
LIMIT 10;
|
|
*/
|
|
|
|
-- =====================================================================
|
|
-- NOTAS POST-IMPLEMENTACIÓN
|
|
-- =====================================================================
|
|
/*
|
|
1. Monitorear pg_stat_user_indexes para verificar uso:
|
|
SELECT * FROM pg_stat_user_indexes WHERE indexrelname LIKE 'idx_scanning%';
|
|
|
|
2. Si un índice no se usa después de 1 semana, considerar eliminarlo
|
|
|
|
3. Ejecutar REINDEX periódicamente si hay muchos UPDATEs/DELETEs:
|
|
REINDEX INDEX CONCURRENTLY idx_scanning_report_network_date_person;
|
|
|
|
4. Próximo paso: Implementar Fase 2 (pre-calcular timezone fields)
|
|
*/
|
|
|
|
-- =====================================================================
|
|
-- FIN DE FASE 1
|
|
-- =====================================================================
|