# Informe de rendimiento INVIMA

Generado: 2026-07-12T23:11:54.172Z

## 1. Infraestructura

Infraestructura minima de referencia declarada: 4 GB RAM, 2 vCPU compartidas, 80 GB de almacenamiento, 4 TB de transferencia mensual y red nominal de hasta 40 Gbps de entrada / 4 Gbps de salida. Las versiones reales del entorno se registran con `npm run benchmark:resources` en `benchmarks/results/resource_snapshot.json`.

## 2. Condiciones de prueba

El protocolo completo usa 5 repeticiones de calentamiento por consulta, 100 repeticiones medidas por cada una de las siete consultas y 100 solicitudes por cada nivel de concurrencia (1, 5, 10, 25, 50 usuarios virtuales). El calentamiento no se incluye en metricas.

## 3. Estado del servidor antes de iniciar

Ver `benchmarks/results/resource_snapshot.json`. Si el archivo no existe, ejecute `npm run benchmark:resources`.

## 4. Consultas evaluadas

| ID |Consulta |Grupo |Endpoint asociado |
| --- |--- |--- |--- |
| query_01 |COUNT total de invima_api_catalog |estructurada |GET /api/invima/sync/stats |
| query_02 |Catalogo general paginado LIMIT 25 |estructurada |GET /api/invima/catalogo?limit=25&offset=0 |
| query_03 |Conteo de dispositivos |estructurada |SQL directo de evaluacion |
| query_04 |Conteo de dispositivos vigentes |estructurada |SQL directo de evaluacion |
| query_05 |Filtro dispositivos vigentes LIMIT 25 |estructurada |GET /api/invima/catalogo?datasets=dispositivos&onlyVigentes=true&limit=25&offset=0 |
| query_06 |Busqueda textual real del backend para marcapasos LIMIT 25 |busqueda_textual |GET /api/invima/catalogo?q=marcapasos&limit=25&offset=0 |
| query_07 |Conteo de busqueda textual real para marcapasos |busqueda_textual |GET /api/invima/catalogo?q=marcapasos&limit=25&offset=0 ejecuta conteo interno |

## 5. Metodologia

Cada ejecucion usa `EXPLAIN (ANALYZE, BUFFERS, VERBOSE, FORMAT JSON)`, registra latencia total de la operacion SQL, tiempos de planeacion y ejecucion de PostgreSQL, filas estimadas y reales, buffers, estado de exito o fallo, CPU/memoria del proceso de benchmark y conexiones activas a PostgreSQL. Los campos de HTTP quedan como `SQL_ONLY` porque estas siete consultas fueron identificadas como mediciones SQL representativas; los endpoints asociados se documentan para trazabilidad.

## 6. Resultados por consulta - linea base

| Consulta |Grupo |n |Promedio ms |p95 ms |p99 ms |CV |Fallos |Throughput/s |Criterio |
| --- |--- |--- |--- |--- |--- |--- |--- |--- |--- |
| query_01 |estructurada |100 |180,8483 |221,0414 |224,5531 |13,3858 % |0 |5,5463 |Cumple latencia estructurada |
| query_02 |estructurada |100 |0,7436 |1,5573 |1,7209 |45,2219 % |0 |465,1163 |No cumple latencia estructurada |
| query_03 |estructurada |100 |62,1545 |152,5783 |160,9022 |73,9718 % |0 |16,0565 |No cumple latencia estructurada |
| query_04 |estructurada |100 |336,9629 |378,5169 |440,6483 |8,1322 % |0 |2,9818 |Cumple latencia estructurada |
| query_05 |estructurada |100 |358,2494 |387,7051 |400,0415 |5,6379 % |0 |2,8108 |Cumple latencia estructurada |
| query_06 |busqueda_textual |100 |58,9326 |63,0636 |64,1303 |6,0973 % |0 |16,5673 |Cumple latencia textual |
| query_07 |busqueda_textual |100 |55,7683 |60,3065 |61,3194 |5,4861 % |0 |17,4551 |Cumple latencia textual |

## 7. Resultados de concurrencia

| Usuarios |Consulta |n |Promedio ms |p95 ms |Fallos |Throughput/s |
| --- |--- |--- |--- |--- |--- |--- |
| 1 |query_01 |15 |162,091 |188,2455 |0 |0,8095 |
| 1 |query_02 |15 |8,1895 |10,317 |0 |0,8091 |
| 1 |query_03 |14 |85,0922 |167,6209 |0 |0,8153 |
| 1 |query_04 |14 |273,713 |298,8697 |0 |0,8217 |
| 1 |query_05 |14 |296,5542 |324,1339 |0 |0,8164 |
| 1 |query_06 |14 |41,1734 |46,6509 |0 |0,8203 |
| 1 |query_07 |14 |26,717 |29,6636 |0 |0,8206 |
| 5 |query_01 |15 |247,5794 |358,828 |0 |2,9297 |
| 5 |query_02 |15 |15,2027 |24,1378 |0 |2,9143 |
| 5 |query_03 |14 |69,9716 |175,6754 |0 |2,8513 |
| 5 |query_04 |14 |513,248 |692,9919 |0 |2,8346 |
| 5 |query_05 |14 |544,4535 |885,0376 |0 |2,7978 |
| 5 |query_06 |14 |60,2426 |73,7649 |0 |2,7767 |
| 5 |query_07 |14 |52,3304 |66,0039 |0 |2,805 |
| 10 |query_01 |15 |587,9522 |997,1856 |0 |3,9093 |
| 10 |query_02 |15 |19,77 |27,073 |0 |3,874 |
| 10 |query_03 |14 |65,1973 |128,5397 |0 |3,8642 |
| 10 |query_04 |14 |759,8982 |1.173,3659 |0 |3,7645 |
| 10 |query_05 |14 |764,3358 |1.213,4999 |0 |3,7175 |
| 10 |query_06 |14 |70,4471 |91,1849 |0 |3,7665 |
| 10 |query_07 |14 |60,9191 |91,6887 |0 |3,876 |
| 25 |query_01 |15 |897,0712 |1.345,1214 |0 |4,7589 |
| 25 |query_02 |15 |21,7858 |79,3087 |0 |4,8765 |
| 25 |query_03 |14 |119,665 |388,4036 |0 |4,8276 |
| 25 |query_04 |14 |1.634,4797 |2.308,0738 |0 |4,8093 |
| 25 |query_05 |14 |1.681,5317 |2.426,8691 |0 |4,5692 |
| 25 |query_06 |14 |87,642 |133,2468 |0 |4,5767 |
| 25 |query_07 |14 |88,2408 |138,4633 |0 |4,5797 |
| 50 |query_01 |15 |1.233,3936 |1.800,638 |0 |5,6775 |
| 50 |query_02 |15 |18,209 |54,6435 |0 |6,1551 |
| 50 |query_03 |14 |390,1372 |1.213,9514 |0 |5,5031 |
| 50 |query_04 |14 |1.919,628 |2.568,4577 |0 |5,283 |
| 50 |query_05 |14 |2.087,0267 |2.686,7188 |0 |5,9473 |
| 50 |query_06 |14 |118,3391 |233,0683 |0 |6,4015 |
| 50 |query_07 |14 |111,4119 |327,4249 |0 |5,4117 |
| 1 |agregado |100 |126,797 |294,5365 |0 |5,333 |
| 5 |agregado |100 |213,0518 |590,6394 |0 |18,9861 |
| 10 |agregado |100 |332,07 |950,6843 |0 |25,8264 |
| 25 |agregado |100 |643,4468 |2.060,2028 |0 |31,5358 |
| 50 |agregado |100 |835,4564 |2.308,4586 |0 |37,594 |

## 8. Recursos

Los resultados crudos incluyen CPU del proceso, memoria RSS, operaciones de lectura/escritura reportadas por Node.js y conexiones activas. Para CPU/RAM del servidor y PostgreSQL se debe complementar con herramientas del sistema operativo si se requiere granularidad por proceso.

## 9. EXPLAIN ANALYZE

Cada fila cruda conserva planeacion, ejecucion, filas estimadas/reales y buffers. Para conservar el plan JSON completo, use una corrida puntual con `BENCHMARK_REPETITIONS=1` o exporte desde PostgreSQL si se requiere auditoria completa de planes.

## 10. Optimizaciones aplicadas

Las optimizaciones reversibles estan en `benchmarks/migrations/optimization_up.sql` y `benchmarks/migrations/optimization_down.sql`. Incluyen indices B-tree para orden/filtros frecuentes, indices GIN trigram para los campos usados por `ILIKE '%marcapasos%'`, aumento de estadisticas por columna y `ANALYZE`.

## 11. Comparacion antes/despues

| Consulta |Grupo |n |Promedio ms |p95 ms |p99 ms |CV |Fallos |Throughput/s |Criterio |
| --- |--- |--- |--- |--- |--- |--- |--- |--- |--- |
| query_01 |estructurada |100 |189,6095 |228,973 |232,9723 |12,2207 % |0 |5,2851 |Cumple latencia estructurada |
| query_02 |estructurada |100 |1,2464 |2,0078 |2,2535 |39,9475 % |0 |343,6426 |No cumple latencia estructurada |
| query_03 |estructurada |100 |64,6984 |158,8514 |175,4067 |71,8252 % |0 |15,223 |No cumple latencia estructurada |
| query_04 |estructurada |100 |339,9853 |383,8868 |438,182 |7,1143 % |0 |2,959 |Cumple latencia estructurada |
| query_05 |estructurada |100 |360,2395 |391 |393,1633 |5,3055 % |0 |2,7926 |Cumple latencia estructurada |
| query_06 |busqueda_textual |100 |61,0332 |68,2614 |75,1879 |7,21 % |0 |15,873 |Cumple latencia textual |
| query_07 |busqueda_textual |100 |58,6218 |65,3004 |72,1182 |6,7621 % |0 |16,5893 |Cumple latencia textual |

## 12. Criterios cumplidos y no cumplidos

No se declara cumplimiento sin resultados crudos. Cuando existan CSV completos, esta seccion debe leerse junto con las columnas `criterio`, `failure_rate_percent`, `latency_p95_ms` y `latency_p99_ms`.

## 13. Limitaciones

- Las siete consultas representan mediciones SQL; el tiempo HTTP real requiere ejecutar el backend, autenticar y medir endpoints con token.
- La busqueda textual real combina FTS con varios `ILIKE`, lo cual puede ser costoso.
- Ejecutar 1 200 operaciones completas puede tardar mucho si las busquedas textuales mantienen tiempos del orden de decenas de segundos.
- EA, MSE, precision y exhaustividad no calculables por ausencia de un conjunto de referencia validado.

## 14. Recomendaciones

- Ejecutar primero una prueba corta con `BENCHMARK_REPETITIONS=1 BENCHMARK_CONCURRENCY_REQUESTS=7`.
- Ejecutar el protocolo completo en una ventana controlada.
- Revisar planes de `query_06` y `query_07` antes y despues de los indices trigram.
- Considerar una refactorizacion futura de busqueda textual para usar una columna `tsvector` persistida o una estrategia de union controlada, sin eliminar campos validos.
