Resultados: simplificación de la query de Cargo/Abono (v0.3)

Contexto y encargo original: contexto_v03_simplificar.md. Query ganadora: queries/gastos/cargo_abono_folio_v03_simplificada.sql. Script de iteración (reproducible): queries/gastos/_iterar_v03.py.

Punto de partida

Query actual (árbol recursivo sobre Grupo_Cuenta_Contable + CASE de 4 niveles para Abono), corrida tal cual contra v01_baseline_enero2026_sin_nomina_consumo.csv:

  • 99.7% de reconciliación (1421/1425 folios) — confirma el número documentado.
  • Los 4 folios que fallan son exactamente los ya conocidos: 0001-0034998, 0001-0034999, 0005-0181359 (reversiones contables) y 0005-0177136 (GASTO_RECLASIFICACION).

Iteración: 8 variantes probadas

Cada variante mide (CARGO - ABONO) - IMPORTE contra el mismo baseline; se considera reconciliado si la diferencia es < $1.

VarianteQué le quita al baselineJoins extra% reconcilia
V0 — baseline actual—Cuenta_Contable + CTE recursivo99.7% (1421/1425)
V1 — Cc_Grupo_Cuenta_Contable directoárbol recursivoCuenta_Contable99.4% (1417/1425)
V2 — cuenta='6' + fallback descripciónárbol + chequeo de grupoCuenta_Contable99.6% (1420/1425)
V3 — solo LEFT(cuenta,1)='6'árbol + join a Cuenta_Contable + 3 de 4 ramas del CASEninguno99.6% (1419/1425)
V4 — solo Cargo, sin Abonotodo lo de Abononinguno99.4% (1417/1425)
V5 — Cargo − todo el Abono sin filtrarel filtro de cuenta (control)ninguno90.6% (1291/1425)
V6 — árbol recursivo, solo raíz=‘F’2 de 4 ramas del CASE (mantiene árbol)Cuenta_Contable + CTE99.6% (1420/1425)
V7 — cuenta ∈ (‘5’,‘6’)igual que V3 pero rango más amplioninguno99.6% (1419/1425)

Hallazgo clave: casi toda la reconciliación viene de la parte de Cargo; el Abono con lógica de árbol completo (V0) solo rescata 4 folios más que quitarlo del todo (V4), y solo 2 folios más que quedarse con una única condición sobre Cc_Cve_Cuenta_Contable que ya vive en Poliza_Detalle (V3, sin joins extra).

Variante ganadora: V3

SUM(CASE WHEN Pd_Tipo=2 AND LEFT(Cc_Cve_Cuenta_Contable,1)='6' THEN Pd_Importe ELSE 0 END)

  • 99.6% (1419/1425), solo 0.1pp por debajo del baseline de 99.7%.
  • Sin CTE recursivo, sin join a Cuenta_Contable ni a Grupo_Cuenta_Contable: la única condición de Abono usa una columna que ya está en Poliza_Detalle.
  • Comparada con V4 (quitar Abono del todo, misma cantidad de joins: cero extra), la condición de cuenta=‘6’ es prácticamente gratis en complejidad y recupera 2 folios más — no hay razón para preferir V4.
  • Se descartó buscar más allá de 99.6% (V0/V2/V6 llegan a 99.6–99.7%) porque eso exige reintroducir el árbol recursivo y/o el join a Cuenta_Contable que esta simplificación existe para evitar; el piso pedido era 80%.

Folios que no reconcilian con V3 (6 de 1425, 0.4%) — los mismos 4 ya documentados más 2 nuevos, ambos de causa conocida (Abono real que cae en el fallback de descripción o en una rama del árbol que no resuelve a raíz ‘F’ pero tampoco tiene prefijo de cuenta ‘6’):

0001-0034998, 0001-0034999, 0005-0181359   -- reversiones (Importe <= -$1)
0005-0177136                                -- GASTO_RECLASIFICACION
0005-0176654, 0007-0082476                  -- Abono fuera de cuenta '6' (nuevos)

Benchmark de velocidad (5 corridas c/u, incluye ida y vuelta a la BD)

VarianteMin (s)Prom (s)
V0 — baseline actual0.6360.745
V3 — ganadora0.1470.156
V4 — solo Cargo0.1500.159
V5 — Cargo−Abono sin filtrar0.1370.165

V3, V4 y V5 comparten el mismo grafo de joins (ninguno extra sobre la cadena base Gasto_Registro → Poliza_Control → Poliza → Poliza_Detalle), así que su tiempo es esencialmente el mismo (~0.15s); las diferencias entre ellas están dentro del ruido de red/servidor. V0 es 4-5x más lenta por el CTE recursivo sobre Grupo_Cuenta_Contable y el join extra a Cuenta_Contable.

V5 es marginalmente la más rápida pero solo reconcilia 90.6% — no vale la pena sacrificar ~9 puntos de reconciliación por ~10-15 milisegundos.

Bugs evitados (no reintroducidos)

Los 4 bugs documentados en contexto_v03_simplificar.md (colisión de Gr_Folio entre sucursales, colisión de Pd_Referencia entre años, comparación contra TOTAL con IVA en vez de SUBTOTAL, filtro de empresa vía Sucursal.Em_Cve_Empresa) se mantienen intactos en V3: la cadena de joins (Poliza_Control por Pc_Documento, Poliza_Detalle por Pd_Referencia acotado por Pl_Folio) es idéntica a la del baseline; solo cambió la condición de Abono.

Alcance

Todo a nivel folio — no se implementó atribución por documento (Gasto_Registro_Control), fuera del alcance de esta tarea.