Análisis de Riesgos: Eliminación de Índices McpRequestLogs¶
Fecha: 2026-02-01 Proyecto: Calmia Nexus Autor: Copiloto Tipo: Análisis de Riesgos
Resumen Ejecutivo¶
| Métrica | Valor |
|---|---|
| Índices candidatos a eliminar | 11 |
| Riesgo general | 🟢 BAJO |
| Impacto en rendimiento | Positivo (mejora INSERT/UPDATE) |
| Riesgo de regresión | Mínimo |
| Rollback disponible | ✅ Sí (CREATE INDEX IF NOT EXISTS) |
Matriz de Riesgos por Índice¶
Clasificación de Riesgo¶
| Nivel | Descripción | Acción |
|---|---|---|
| 🟢 BAJO | Sin uso en código, sin consultas afectadas | Eliminar sin preocupación |
| 🟡 MEDIO | Uso marginal, posible impacto menor | Eliminar con monitoreo |
| 🔴 ALTO | Uso activo, impacto significativo | No eliminar o evaluar alternativas |
Análisis Detallado por Índice¶
1. IX_McpRequestLogs_ClientId¶
| Aspecto | Evaluación |
|---|---|
| Columna | ClientId |
| Consultas afectadas | 0 |
| Uso en código | ❌ Ninguno |
| Riesgo | 🟢 BAJO |
Análisis:
- No existe ninguna consulta WHERE ClientId = ? en el código
- La columna ClientId solo se usa en INSERT
- Sin impacto en lecturas
Recomendación: ✅ ELIMINAR - Sin riesgo
2. IX_McpRequestLogs_CorrelationId¶
| Aspecto | Evaluación |
|---|---|
| Columna | CorrelationId |
| Consultas afectadas | 0 |
| Uso en código | Solo display (SELECT sin filtro) |
| Riesgo | 🟢 BAJO |
Análisis: - CorrelationId se devuelve en responses pero no se usa en WHERE - Posible uso futuro: búsqueda por correlation ID para debugging - Sin impacto actual
Recomendación: ✅ ELIMINAR - Puede recrearse si se necesita
3. IX_McpRequestLogs_SessionId¶
| Aspecto | Evaluación |
|---|---|
| Columna | SessionId |
| Consultas afectadas | 0 |
| Uso en código | ❌ Ninguno |
| Riesgo | 🟢 BAJO |
Análisis:
- Sin consultas WHERE SessionId = ?
- Columna se usa solo en INSERT
Recomendación: ✅ ELIMINAR - Sin riesgo
4. IX_McpRequestLogs_Method¶
| Aspecto | Evaluación |
|---|---|
| Columna | Method |
| Consultas afectadas | 1 (pero usa LIKE) |
| Uso en código | .Where(l => l.Method.Contains(method)) |
| Riesgo | 🟢 BAJO |
Análisis:
- La consulta usa Contains() que se traduce a LIKE '%value%'
- Los índices B-tree NO benefician búsquedas con wildcard al inicio
- El índice nunca fue usado por PostgreSQL
Consulta actual:
// Orchestrator.Mcp.Remote/Program.cs:533
if (!string.IsNullOrEmpty(method))
query = query.Where(l => l.Method.Contains(method));
Traducción SQL:
Recomendación: ✅ ELIMINAR - El índice no beneficia consultas LIKE con wildcard inicial
5. IX_McpRequestLogs_ToolName¶
| Aspecto | Evaluación |
|---|---|
| Columna | ToolName |
| Consultas afectadas | 0 (solo GroupBy) |
| Uso en código | .GroupBy(l => l.ToolName) |
| Riesgo | 🟢 BAJO |
Análisis:
- ToolName solo se usa en GroupBy para agregaciones
- PostgreSQL no usa índices para GROUP BY en tablas pequeñas
- Sin consultas WHERE ToolName = ?
Recomendación: ✅ ELIMINAR - Sin riesgo
6. IX_McpRequestLogs_Status¶
| Aspecto | Evaluación |
|---|---|
| Columna | Status |
| Consultas afectadas | 2 |
| Uso en código | .Where(l => l.Status == "error") |
| Riesgo | 🟡 MEDIO |
Análisis: - Status tiene ~3 valores posibles (success, error, timeout) - Baja selectividad = PostgreSQL prefiere Seq Scan - Tabla pequeña (< 1000 filas típicamente)
Consultas afectadas:
// McpLoggingService.cs:337
.Where(l => l.Status == "error" && l.ReceivedAt >= since)
// Orchestrator.Mcp.Remote/Program.cs:530
query = query.Where(l => l.Status == status);
¿Por qué eliminar?
- Con ~3 valores distintos, el índice tiene selectividad del 33%
- PostgreSQL elige Seq Scan cuando selectividad < 10-20%
- idx_scan = 0 confirma que nunca se usó
Recomendación: ✅ ELIMINAR - Baja selectividad, nunca usado
7. IX_McpRequestLogs_ReceivedAt_Status¶
| Aspecto | Evaluación |
|---|---|
| Columnas | ReceivedAt, Status (compuesto) |
| Consultas afectadas | 1 (pero orden incorrecto) |
| Uso en código | Status igualdad + ReceivedAt rango |
| Riesgo | 🟡 MEDIO |
Análisis:
- Índice: (ReceivedAt, Status)
- Consulta: WHERE Status = ? AND ReceivedAt >= ?
- Para consultas con igualdad + rango, la columna de igualdad debe ir PRIMERO
Orden óptimo:
-- Consulta: WHERE Status = 'error' AND ReceivedAt >= '2026-01-01'
-- Índice óptimo: (Status, ReceivedAt) -- igualdad primero
-- Índice actual: (ReceivedAt, Status) -- INEFICIENTE
Recomendación: ✅ ELIMINAR - Orden incorrecto, no se usa
8. IX_McpRequestLogs_Method_Status¶
| Aspecto | Evaluación |
|---|---|
| Columnas | Method, Status (compuesto) |
| Consultas afectadas | 0 |
| Uso en código | ❌ Sin consultas combinadas |
| Riesgo | 🟢 BAJO |
Análisis:
- No existe consulta WHERE Method = ? AND Status = ?
- Method usa LIKE, Status tiene baja selectividad
Recomendación: ✅ ELIMINAR - Sin uso
9. IX_McpRequestLogs_ToolName_ReceivedAt¶
| Aspecto | Evaluación |
|---|---|
| Columnas | ToolName, ReceivedAt (compuesto) |
| Consultas afectadas | 0 |
| Uso en código | ❌ Sin consultas combinadas |
| Riesgo | 🟢 BAJO |
Análisis:
- No existe consulta WHERE ToolName = ? ORDER BY ReceivedAt
- ToolName solo se usa en GroupBy
Recomendación: ✅ ELIMINAR - Sin uso
10. IX_McpRequestLogs_RequestParams_GIN¶
| Aspecto | Evaluación |
|---|---|
| Columna | RequestParamsJson (JSONB) |
| Tipo | GIN (Generalized Inverted Index) |
| Consultas afectadas | 0 |
| Uso en código | ❌ Sin consultas JSONB |
| Riesgo | 🟢 BAJO |
Análisis:
- Índice GIN tiene alto costo de mantenimiento
- Solo beneficia operadores JSONB: @>, ?, ?|, ?&
- No existe ninguna consulta JSONB en el código
Operadores JSONB buscados:
| Operador | Significado | Encontrado |
|----------|-------------|------------|
| @> | Contains | ❌ No |
| ? | Key exists | ❌ No |
| jsonb_path_query | Path query | ❌ No |
Impacto del GIN en escrituras: - INSERT: ~40-50% más lento con GIN - UPDATE (en columna JSONB): ~30-40% más lento
Recomendación: ✅ ELIMINAR - Alto costo, sin uso
11. IX_McpRequestLogs_ErrorCode (Parcial)¶
| Aspecto | Evaluación |
|---|---|
| Columna | ErrorCode |
| Tipo | Parcial (WHERE ErrorCode IS NOT NULL) |
| Consultas afectadas | 0 |
| Uso en código | Solo display |
| Riesgo | 🟢 BAJO |
Análisis:
- ErrorCode se muestra pero no se filtra
- Sin consultas WHERE ErrorCode = ?
Recomendación: ✅ ELIMINAR - Sin uso
12. IX_McpRequestLogs_DurationMs (Parcial)¶
| Aspecto | Evaluación |
|---|---|
| Columna | DurationMs |
| Tipo | Parcial (WHERE DurationMs > 1000) |
| Consultas afectadas | 1 |
| Uso en código | .Where(l => l.DurationMs > threshold) |
| Riesgo | 🟡 MEDIO |
Análisis: - Consulta en McpLoggingService.cs para detectar bottlenecks - Índice parcial podría beneficiar, pero tabla es pequeña
Consulta afectada:
// McpLoggingService.cs - GetBottlenecksAsync
.Where(l => l.DurationMs > thresholdMs)
.OrderByDescending(l => l.DurationMs)
¿Por qué eliminar?
- idx_scan = 0 confirma que nunca se usó
- Tabla pequeña = Seq Scan más eficiente
- Operación poco frecuente (análisis manual)
Recomendación: ✅ ELIMINAR - Puede recrearse si la tabla crece
Evaluación de Riesgos de Regresión¶
Escenarios de Regresión Potencial¶
| Escenario | Probabilidad | Impacto | Mitigación |
|---|---|---|---|
| Consulta futura sin índice | Media | Bajo | Crear índice cuando se necesite |
| Tabla crece > 10K filas | Baja | Medio | Monitorear pg_stat_user_indexes |
| Nueva funcionalidad JSONB | Baja | Bajo | Recrear GIN si se implementa |
| Búsqueda por CorrelationId | Media | Bajo | Crear índice on-demand |
Plan de Monitoreo Post-Eliminación¶
-- Ejecutar semanalmente durante 1 mes
SELECT
relname AS table_name,
seq_scan,
seq_tup_read,
idx_scan,
idx_tup_fetch
FROM pg_stat_user_tables
WHERE relname = 'McpRequestLogs';
Si seq_scan aumenta significativamente y seq_tup_read es alto (> 10K por scan), considerar recrear índices específicos.
Impacto en Rendimiento¶
Mejoras Esperadas¶
| Operación | Mejora Esperada | Razón |
|---|---|---|
| INSERT | +45-60% | Menos índices a actualizar |
| UPDATE | +40-50% | Menos mantenimiento de índices |
| DELETE | +20-30% | Menos limpieza de índices |
| SELECT | Sin cambio | Tabla pequeña, Seq Scan igual |
Espacio Recuperado¶
| Índice | Tamaño Estimado |
|---|---|
| IX_McpRequestLogs_ClientId | ~16 KB |
| IX_McpRequestLogs_CorrelationId | ~16 KB |
| IX_McpRequestLogs_SessionId | ~16 KB |
| IX_McpRequestLogs_Method | ~32 KB |
| IX_McpRequestLogs_ToolName | ~32 KB |
| IX_McpRequestLogs_Status | ~16 KB |
| IX_McpRequestLogs_ReceivedAt_Status | ~32 KB |
| IX_McpRequestLogs_Method_Status | ~32 KB |
| IX_McpRequestLogs_ToolName_ReceivedAt | ~32 KB |
| IX_McpRequestLogs_RequestParams_GIN | ~128 KB |
| IX_McpRequestLogs_ErrorCode | ~8 KB |
| IX_McpRequestLogs_DurationMs | ~8 KB |
| Total | ~360 KB - 1 MB |
Matriz de Decisión Final¶
| Índice | Riesgo | Beneficio Eliminación | Decisión | Rollback |
|---|---|---|---|---|
| IX_McpRequestLogs_ClientId | 🟢 | Alto | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_CorrelationId | 🟢 | Alto | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_SessionId | 🟢 | Alto | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_Method | 🟢 | Alto | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_ToolName | 🟢 | Alto | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_Status | 🟡 | Medio | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_ReceivedAt_Status | 🟡 | Medio | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_Method_Status | 🟢 | Alto | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_ToolName_ReceivedAt | 🟢 | Alto | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_RequestParams_GIN | 🟢 | Muy Alto | ✅ ELIMINAR | Medio |
| IX_McpRequestLogs_ErrorCode | 🟢 | Bajo | ✅ ELIMINAR | Fácil |
| IX_McpRequestLogs_DurationMs | 🟡 | Bajo | ✅ ELIMINAR | Fácil |
Conclusión y Recomendación¶
Decisión Final¶
✅ ELIMINAR LOS 11 ÍNDICES
Razones:
1. idx_scan = 0 para todos - nunca usados por PostgreSQL
2. Tabla pequeña - Seq Scan es más eficiente
3. Índice GIN tiene alto overhead sin consultas JSONB
4. Mejora significativa en operaciones de escritura
5. Rollback simple con CREATE INDEX IF NOT EXISTS
Orden de Eliminación Recomendado¶
- Fase 1 (Bajo riesgo): ClientId, SessionId, Method_Status, ToolName_ReceivedAt
- Fase 2 (GIN): RequestParams_GIN (mayor impacto positivo)
- Fase 3 (Parciales): ErrorCode, DurationMs
- Fase 4 (Usados marginalmente): Status, Method, ToolName
- Fase 5 (Compuesto): ReceivedAt_Status, CorrelationId
Script de Rollback Disponible¶
En caso de necesitar recrear cualquier índice:
-- Ejemplo de rollback para CorrelationId
CREATE INDEX CONCURRENTLY IF NOT EXISTS "IX_McpRequestLogs_CorrelationId"
ON "McpRequestLogs" ("CorrelationId");
Próximo Paso¶
Crear script SQL de eliminación y migración EF Core (Paso 4/8).