FASE 7b: DB Performance — Pooling, Stock Summary, N+1 fix

Cambios implementados:

1. Connection pooling (tenant_db.py):
   - psycopg2.pool.ThreadedConnectionPool para master y tenants
   - Wrapper _PooledConnection que devuelve al pool en .close()
   - Cero cambios en blueprints (backward compatible)

2. Tabla inventory_stock_summary + triggers (v3.2):
   - O(1) stock lookup en vez de SUM() sobre historial completo
   - Trigger AFTER INSERT en inventory_operations recalcula stock
   - Poblada inicialmente en ambos tenants
   - Refactor en 6 archivos de servicios para usar la nueva tabla

3. Fix N+1 en process_sale (pos_engine.py):
   - Precarga retail_price en bulk query FOR UPDATE
   - Elimina SELECT individual por item en loop

4. Índices críticos:
   - idx_parts_name_part + pattern_ops (master)
   - idx_inv_ops_inventory_branch_created (tenants)
   - idx_wi_part_stock_positive (master, ya existía desde Fase 1)

Tests: 73/73 pasando (compat + fase3 + fase5 + fase6)
Migración: v3.2_db_performance.sql
This commit is contained in:
2026-04-27 07:34:31 +00:00
parent 175dda6212
commit e3c85fd647
9 changed files with 173 additions and 40 deletions

View File

@@ -1411,12 +1411,11 @@ def _get_local_stock_bulk(tenant_conn, branch_id, oem_numbers, catalog_part_ids)
cur.execute(f"""
SELECT i.id, i.part_number, i.catalog_part_id,
i.price_1, i.price_2, i.price_3, i.cost, i.tax_rate,
COALESCE(SUM(io.quantity), 0) AS stock,
COALESCE(s.stock, 0) AS stock,
i.image_url
FROM inventory i
LEFT JOIN inventory_operations io ON io.inventory_id = i.id
LEFT JOIN inventory_stock_summary s ON s.inventory_id = i.id
WHERE ({where}) AND i.is_active = true{branch_filter}
GROUP BY i.id
""", params)
result = {}
@@ -1453,13 +1452,12 @@ def _get_local_stock_single(tenant_conn, branch_id, oem_part_number, catalog_par
cur.execute(f"""
SELECT i.id, i.price_1, i.price_2, i.price_3, i.cost, i.tax_rate,
i.location, i.unit, i.barcode,
COALESCE(SUM(io.quantity), 0) AS stock,
COALESCE(s.stock, 0) AS stock,
i.image_url
FROM inventory i
LEFT JOIN inventory_operations io ON io.inventory_id = i.id
LEFT JOIN inventory_stock_summary s ON s.inventory_id = i.id
WHERE (i.part_number = %s OR i.catalog_part_id = %s)
AND i.is_active = true{branch_filter}
GROUP BY i.id
LIMIT 1
""", params)