Try to speed up brand calcs

This commit is contained in:
2025-02-10 10:20:32 -05:00
parent d936d50f83
commit 3d2d1b3946

View File

@@ -138,11 +138,11 @@ async function calculateBrandMetrics(startTime, totalProducts, processedCount =
p.brand,
COUNT(DISTINCT p.pid) as product_count,
COUNT(DISTINCT CASE WHEN p.visible = true THEN p.pid END) as active_products,
SUM(p.stock_quantity) as total_stock_units,
SUM(p.stock_quantity * p.cost_price) as total_stock_cost,
SUM(p.stock_quantity * p.price) as total_stock_retail,
SUM(pm.total_revenue) as total_revenue,
AVG(pm.avg_margin_percent) as avg_margin
COALESCE(SUM(p.stock_quantity), 0) as total_stock_units,
COALESCE(SUM(p.stock_quantity * p.cost_price), 0) as total_stock_cost,
COALESCE(SUM(p.stock_quantity * p.price), 0) as total_stock_retail,
COALESCE(SUM(pm.total_revenue), 0) as total_revenue,
COALESCE(AVG(NULLIF(pm.avg_margin_percent, 0)), 0) as avg_margin
FROM products p
FORCE INDEX (idx_brand)
LEFT JOIN product_metrics pm FORCE INDEX (PRIMARY) ON p.pid = pm.pid
@@ -158,32 +158,42 @@ async function calculateBrandMetrics(startTime, totalProducts, processedCount =
GROUP BY p.brand
`, [batch.map(row => row.brand), lastCalculationTime, lastCalculationTime]);
// Populate sales stats with optimized index usage
// Populate sales stats with optimized date handling
await connection.query(`
INSERT INTO temp_sales_stats
WITH date_ranges AS (
SELECT
DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY) as current_start,
CURRENT_DATE as current_end,
DATE_SUB(CURRENT_DATE, INTERVAL 60 DAY) as previous_start,
DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY) as previous_end
)
SELECT
p.brand,
SUM(CASE
WHEN o.date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
COALESCE(SUM(
CASE WHEN o.date >= dr.current_start
THEN o.quantity * o.price
ELSE 0
END) as current_period_sales,
SUM(CASE
WHEN o.date BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 60 DAY) AND DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
END
), 0) as current_period_sales,
COALESCE(SUM(
CASE WHEN o.date >= dr.previous_start AND o.date < dr.current_start
THEN o.quantity * o.price
ELSE 0
END) as previous_period_sales
END
), 0) as previous_period_sales
FROM products p
FORCE INDEX (idx_brand)
INNER JOIN orders o FORCE INDEX (idx_orders_metrics) ON p.pid = o.pid
AND o.canceled = false
AND o.date >= DATE_SUB(CURRENT_DATE, INTERVAL 60 DAY)
AND o.updated > ?
CROSS JOIN date_ranges dr
WHERE p.brand IN (?)
AND o.canceled = false
AND o.date >= dr.previous_start
AND o.updated > ?
GROUP BY p.brand
`, [lastCalculationTime, batch.map(row => row.brand)]);
`, [batch.map(row => row.brand), lastCalculationTime]);
// Update metrics using temp tables
// Update metrics using temp tables with optimized calculations
await connection.query(`
INSERT INTO brand_metrics (
brand,
@@ -199,19 +209,19 @@ async function calculateBrandMetrics(startTime, totalProducts, processedCount =
)
SELECT
ps.brand,
COALESCE(ps.product_count, 0) as product_count,
COALESCE(ps.active_products, 0) as active_products,
COALESCE(ps.total_stock_units, 0) as total_stock_units,
COALESCE(ps.total_stock_cost, 0) as total_stock_cost,
COALESCE(ps.total_stock_retail, 0) as total_stock_retail,
COALESCE(ps.total_revenue, 0) as total_revenue,
COALESCE(ps.avg_margin, 0) as avg_margin,
ps.product_count,
ps.active_products,
ps.total_stock_units,
ps.total_stock_cost,
ps.total_stock_retail,
ps.total_revenue,
ps.avg_margin,
CASE
WHEN COALESCE(ss.previous_period_sales, 0) = 0 AND COALESCE(ss.current_period_sales, 0) > 0 THEN 100
WHEN COALESCE(ss.previous_period_sales, 0) = 0 THEN 0
ELSE LEAST(999.99, GREATEST(-100,
((COALESCE(ss.current_period_sales, 0) / ss.previous_period_sales) - 1) * 100
))
ELSE ROUND(LEAST(999.99, GREATEST(-100,
((ss.current_period_sales / NULLIF(ss.previous_period_sales, 0)) - 1) * 100
)), 2)
END as growth_rate,
NOW() as last_calculated_at
FROM temp_product_stats ps