Saltar a contenido

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:

WHERE "Method" LIKE '%tools/call%'  -- Seq Scan siempre

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

  1. Fase 1 (Bajo riesgo): ClientId, SessionId, Method_Status, ToolName_ReceivedAt
  2. Fase 2 (GIN): RequestParams_GIN (mayor impacto positivo)
  3. Fase 3 (Parciales): ErrorCode, DurationMs
  4. Fase 4 (Usados marginalmente): Status, Method, ToolName
  5. 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).