Optimización de Reportes SICOSS
Cómo reduje un proceso crítico de 40 minutos a menos de 60 segundos transformando consultas SQL masivas y migrando lógica a Python.
Anatomía del Problema (Legacy)
Tras una auditoría técnica profunda, identifiqué dos cuellos de botella que impedían el escalamiento del sistema:
1. SQL Correlacionado (Carga Excesiva de DB)
El sistema original utilizaba subconsultas anidadas de forma correlacionada. Esto significa que por cada registro de liquidación, el motor de base de datos debía recalcular jerarquías de grupos de forma redundante.
-- Representación anonimizada del problema SQL
-- Ejecución redundante de sub-arrays por fila
SELECT
payroll.id,
(SELECT ARRAY(
SELECT DISTINCT group_id
FROM generic_groups_table
WHERE group_id IN (
SELECT group_id FROM concepts_relation
WHERE concept_id = payroll.concept_id
)
)) AS category_groups
FROM payroll_registry AS payroll;2. El problema N+1 en PHP
La lógica de negocio procesaba los legajos de forma secuencial, realizando nuevas peticiones de datos dentro de un bucle de miles de iteraciones.
// Representación anonimizada del flujo ineficiente
foreach ($employees as $employee) {
// Alarma técnica: Consulta a DB dentro de un ciclo masivo
$details = $db->query('SELECT * FROM details WHERE emp_id = ' . $employee['id']);
foreach ($details as $row) {
$this->processBusinessRules($row);
}
}Métricas de Impacto
La Solución
La solución se aplicó en dos etapas críticas:
1. Optimización SQL con CTEs
Reemplacé las subconsultas recurrentes por Common Table Expressions (CTEs). Esto permitió a PostgreSQL precalcullar los grupos una sola vez en memoria y unirlos mediante un Join altamente eficiente.
-- Solución mediante CTE (Pre-procesamiento en memoria)
WITH processed_groups AS (
SELECT concept_id, array_agg(DISTINCT group_id) as groups
FROM concepts_relation
GROUP BY concept_id
)
SELECT payroll.*, pg.groups
FROM payroll_registry payroll
LEFT JOIN processed_groups pg ON pg.concept_id = payroll.concept_id;2. Procesamiento Vectorial con Python
Finalmente, la lógica de validación se migró a un motor en Python utilizando Pandas. Al tratar el millón de registros de forma vectorial (como un todo en memoria), eliminé la sobrecarga del bucle secuencial de PHP.
Conclusión
Este proyecto no solo ahorró tiempo, sino que demostró la importancia de la observabilidad y el análisis de planes de ejecución. La solución fue validada mediante Jupyter Notebooks, asegurando que el 100% de los 1.2M de registros generados coincidieran exactamente con el sistema original, garantizando integridad total de los datos contables.