From 3d2d1b3946de0e9076f52f0a9c7e60fdb57cab9e Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 10 Feb 2025 10:20:32 -0500 Subject: [PATCH] Try to speed up brand calcs --- .../scripts/metrics/brand-metrics.js | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/inventory-server/scripts/metrics/brand-metrics.js b/inventory-server/scripts/metrics/brand-metrics.js index a54ebfb..d80b0cd 100644 --- a/inventory-server/scripts/metrics/brand-metrics.js +++ b/inventory-server/scripts/metrics/brand-metrics.js @@ -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