# Índices y Optimización - Parte 2: Progress, Social y Mantenimiento

**Épica:** EMR-001 - Migración y Robustecimiento de BD
**Fecha:** 2025-11-02
**Origen:** `/docs/03-desarrollo/base-de-datos/INDICES-Y-OPTIMIZACION.md`

---

## 1. Índices de Progress Tracking

### 1.1 progress_tracking.module_progress
```sql
-- Dashboard de usuario
CREATE INDEX idx_module_progress_user_status_updated
    ON module_progress(user_id, status, updated_at DESC);

-- Parciales (OPTIMIZACIÓN CLAVE)
CREATE INDEX idx_module_progress_completed
    ON module_progress(user_id, completed_at DESC)
    WHERE status = 'completed';

CREATE INDEX idx_module_progress_incomplete
    ON module_progress(user_id, updated_at DESC)
    WHERE status IN ('not_started', 'in_progress');
```

**Queries optimizados:**
```sql
-- Módulos en progreso
SELECT * FROM module_progress
WHERE user_id = ? AND status IN ('not_started', 'in_progress')
ORDER BY updated_at DESC;
-- Usa: idx_module_progress_incomplete

-- Módulos completados recientemente
SELECT * FROM module_progress
WHERE user_id = ? AND status = 'completed'
ORDER BY completed_at DESC LIMIT 10;
-- Usa: idx_module_progress_completed
```

---

### 1.2 progress_tracking.exercise_attempts
```sql
-- Historial de intentos
CREATE INDEX idx_exercise_attempts_user_exercise_date
    ON exercise_attempts(user_id, exercise_id, submitted_at DESC);

-- Actividad reciente
CREATE INDEX idx_exercise_attempts_submitted_at
    ON exercise_attempts(submitted_at DESC);
```

---

### 1.3 progress_tracking.learning_sessions
```sql
CREATE INDEX idx_sessions_user_id
    ON learning_sessions(user_id);

CREATE INDEX idx_sessions_started_at
    ON learning_sessions(started_at DESC);

CREATE INDEX idx_sessions_is_active
    ON learning_sessions(is_active);
```

---

## 2. Índices de Social Features

### 2.1 social_features.schools
```sql
CREATE INDEX idx_schools_tenant_id ON schools(tenant_id);
CREATE INDEX idx_schools_code ON schools(code);
CREATE INDEX idx_schools_is_active ON schools(is_active);
```

### 2.2 social_features.classrooms
```sql
CREATE INDEX idx_classrooms_school_id ON classrooms(school_id);
CREATE INDEX idx_classrooms_teacher_id ON classrooms(teacher_id);
CREATE INDEX idx_classrooms_code ON classrooms(code);
```

---

### 2.3 social_features.classroom_members
```sql
-- Listado de estudiantes activos
CREATE INDEX idx_classroom_members_active
    ON classroom_members(classroom_id, status)
    WHERE status = 'active';
```

---

### 2.4 social_features.teams
```sql
-- Leaderboards de equipos
CREATE INDEX idx_teams_classroom_active_xp
    ON teams(classroom_id, is_active, total_xp DESC)
    WHERE is_active = true;
```

---

### 2.5 social_features.team_members
```sql
-- Miembros actuales
CREATE INDEX idx_team_members_active
    ON team_members(team_id)
    WHERE left_at IS NULL;
```

---

## 3. Índices de Content Management

### 3.1 content_management (Marie Curie, Media, Flagged)
```sql
-- Marie Curie Content
CREATE INDEX idx_marie_content_tags_gin ON marie_curie_content USING GIN(search_tags);
CREATE INDEX idx_marie_content_search ON marie_curie_content
    USING GIN(to_tsvector('spanish', coalesce(title, '') || ' ' || coalesce(description, '')));

-- Media Files
CREATE INDEX idx_media_files_media_type ON media_files(media_type);
CREATE INDEX idx_media_files_uploaded_by ON media_files(uploaded_by);
CREATE INDEX idx_media_files_tags_gin ON media_files USING GIN(tags);

-- Flagged Content (moderación)
CREATE INDEX idx_flagged_pending ON flagged_content(priority, created_at DESC)
    WHERE status = 'pending';
```

---

## 4. Índices de System Configuration

```sql
-- System Settings
CREATE INDEX idx_system_settings_key ON system_settings(setting_key);
CREATE INDEX idx_system_settings_category ON system_settings(setting_category);

-- Feature Flags (activos actualmente)
CREATE INDEX idx_feature_flags_active ON feature_flags(feature_key)
    WHERE is_enabled = true
      AND (starts_at IS NULL OR starts_at <= NOW())
      AND (ends_at IS NULL OR ends_at > NOW());
```

---

## 5. Índices de Audit Logging

### 5.1 audit_logging.audit_logs
```sql
CREATE INDEX idx_audit_logs_tenant_id
    ON audit_logs(tenant_id);

CREATE INDEX idx_audit_logs_actor_id
    ON audit_logs(actor_id);

CREATE INDEX idx_audit_logs_resource
    ON audit_logs(resource_type, resource_id);

CREATE INDEX idx_audit_logs_created_at
    ON audit_logs(created_at DESC);

-- Parciales (errores críticos)
CREATE INDEX idx_audit_logs_errors
    ON audit_logs(created_at DESC)
    WHERE severity IN ('error', 'critical');
```

---

### 5.2 audit_logging.system_logs
```sql
-- Errores
CREATE INDEX idx_system_logs_errors
    ON system_logs(created_at DESC)
    WHERE log_level IN ('ERROR', 'FATAL');
```

---

### 5.3 audit_logging.performance_metrics
```sql
CREATE INDEX idx_metrics_name ON performance_metrics(metric_name);
CREATE INDEX idx_metrics_measured_at ON performance_metrics(measured_at DESC);
CREATE INDEX idx_metrics_dimensions_gin ON performance_metrics USING GIN(dimensions);
```

---

### 5.4 audit_logging.system_alerts
```sql
CREATE INDEX idx_alerts_open ON system_alerts(severity, triggered_at DESC)
    WHERE status = 'open';
```

---

## 6. Vista Materializada: Leaderboards

```sql
CREATE MATERIALIZED VIEW gamification_system.leaderboards_view AS
SELECT
    p.id as user_id,
    p.display_name,
    p.avatar_url,
    us.level,
    us.total_xp,
    us.ml_coins,
    us.current_streak,
    us.global_rank_position,
    ur.current_rank as maya_rank,
    p.tenant_id
FROM auth_management.profiles p
JOIN gamification_system.user_stats us ON p.id = us.user_id
JOIN gamification_system.user_ranks ur ON p.id = ur.user_id
  AND ur.is_current = true
WHERE p.status = 'active';

-- Índices en la vista
CREATE UNIQUE INDEX idx_leaderboards_user_id
    ON leaderboards_view(user_id);

CREATE INDEX idx_leaderboards_level
    ON leaderboards_view(level DESC);

CREATE INDEX idx_leaderboards_xp
    ON leaderboards_view(total_xp DESC);

CREATE INDEX idx_leaderboards_tenant_level
    ON leaderboards_view(tenant_id, level DESC);
```

**Refresh Strategy:**
```sql
-- Refresh periódico (cada 5 minutos)
REFRESH MATERIALIZED VIEW CONCURRENTLY leaderboards_view;
```

**Justificación:**
- Leaderboards requieren JOINs pesados
- Query muy frecuente
- Eventually consistent OK (5 min delay)
- CONCURRENTLY permite updates sin bloqueo

---

## 7. Estrategias de Optimización

### 7.1 Índices Parciales - Patrones Comunes

**Usuarios activos:**
```sql
WHERE status = 'active'
```

**Contenido publicado:**
```sql
WHERE is_published = true AND status = 'published'
```

**Sesiones activas:**
```sql
WHERE is_active = true
```

**Alertas abiertas:**
```sql
WHERE status = 'open'
```

**Intentos fallidos (seguridad):**
```sql
WHERE success = false
```

---

### 7.2 Índices GIN - Cuándo Usar

**JSONB:**
- Operadores: `@>`, `?`, `?&`, `?|`
- Ejemplos: `settings`, `preferences`, `metadata`, `content`

**Arrays:**
- Operadores: `@>`, `<@`, `&&`
- Ejemplos: `tags`, `prerequisites`, `used_in_modules`

**Full-Text Search:**
- Operador: `@@`
- Columnas: `tsvector` en español

**Trade-offs:**
- ✅ Búsquedas rápidas en datos semi-estructurados
- ❌ Índices grandes, writes más lentos

---

### 7.3 Full-Text Search (español)

**Implementación:**
```sql
CREATE INDEX idx_modules_search
    ON modules
    USING GIN(to_tsvector('spanish',
        coalesce(title, '') || ' ' || coalesce(description, '')));
```

**Uso:**
```sql
SELECT * FROM modules
WHERE to_tsvector('spanish', title || ' ' || description)
      @@ to_tsquery('spanish', 'marie & curie');
```

**Optimizaciones futuras:**
- Columna `tsvector` generada (evita cálculo en query time)
- Soporte multiidioma (inglés)

---

## 8. Mantenimiento

### 8.1 ANALYZE periódico
```sql
ANALYZE auth_management.profiles;
ANALYZE gamification_system.user_stats;
ANALYZE educational_content.modules;
ANALYZE progress_tracking.module_progress;
```

**Frecuencia:**
- Tablas alta escritura: Diario
- Tablas baja escritura: Semanal

---

### 8.2 Monitoreo de Índices

**Índices no utilizados:**
```sql
SELECT schemaname, tablename, indexname, idx_scan as scans,
    pg_size_pretty(pg_relation_size(indexrelid)) as size
FROM pg_stat_user_indexes
WHERE idx_scan = 0 AND schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_relation_size(indexrelid) DESC;
```

**Tamaño de índices:**
```sql
SELECT schemaname, tablename, indexname,
    pg_size_pretty(pg_relation_size(indexrelid)) as size, idx_scan
FROM pg_stat_user_indexes
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_relation_size(indexrelid) DESC LIMIT 20;
```

---

## 9. Partitioning (Futuro)

**Tablas candidatas:**
- `ml_coins_transactions` - Monthly partitions
- `exercise_attempts` - Quarterly partitions
- `audit_logs` - Monthly partitions
- `user_activity_logs` - Weekly partitions

**Razón:** Tablas de log con crecimiento constante

---

## 10. Referencias

- **Parte 1:** `INDICES-PARTE-1.md` (Auth, Gamificación, Contenido)
- **Esquema:** `ESQUEMA-44-TABLAS.md`
- **Migraciones:** `../01-migraciones/MIGRACIONES-HISTORICO.md`

---

**Última actualización:** 2025-11-02
**Consolidado por:** ARTEMIS (Agente de Migración)
