Compare commits
2 Commits
d936d50f83
...
eea57528ab
| Author | SHA1 | Date | |
|---|---|---|---|
| eea57528ab | |||
| 3d2d1b3946 |
@@ -138,11 +138,11 @@ async function calculateBrandMetrics(startTime, totalProducts, processedCount =
|
|||||||
p.brand,
|
p.brand,
|
||||||
COUNT(DISTINCT p.pid) as product_count,
|
COUNT(DISTINCT p.pid) as product_count,
|
||||||
COUNT(DISTINCT CASE WHEN p.visible = true THEN p.pid END) as active_products,
|
COUNT(DISTINCT CASE WHEN p.visible = true THEN p.pid END) as active_products,
|
||||||
SUM(p.stock_quantity) as total_stock_units,
|
COALESCE(SUM(p.stock_quantity), 0) as total_stock_units,
|
||||||
SUM(p.stock_quantity * p.cost_price) as total_stock_cost,
|
COALESCE(SUM(p.stock_quantity * p.cost_price), 0) as total_stock_cost,
|
||||||
SUM(p.stock_quantity * p.price) as total_stock_retail,
|
COALESCE(SUM(p.stock_quantity * p.price), 0) as total_stock_retail,
|
||||||
SUM(pm.total_revenue) as total_revenue,
|
COALESCE(SUM(pm.total_revenue), 0) as total_revenue,
|
||||||
AVG(pm.avg_margin_percent) as avg_margin
|
COALESCE(AVG(NULLIF(pm.avg_margin_percent, 0)), 0) as avg_margin
|
||||||
FROM products p
|
FROM products p
|
||||||
FORCE INDEX (idx_brand)
|
FORCE INDEX (idx_brand)
|
||||||
LEFT JOIN product_metrics pm FORCE INDEX (PRIMARY) ON p.pid = pm.pid
|
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
|
GROUP BY p.brand
|
||||||
`, [batch.map(row => row.brand), lastCalculationTime, lastCalculationTime]);
|
`, [batch.map(row => row.brand), lastCalculationTime, lastCalculationTime]);
|
||||||
|
|
||||||
// Populate sales stats with optimized index usage
|
// Populate sales stats with optimized date handling
|
||||||
await connection.query(`
|
await connection.query(`
|
||||||
INSERT INTO temp_sales_stats
|
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
|
SELECT
|
||||||
p.brand,
|
p.brand,
|
||||||
SUM(CASE
|
COALESCE(SUM(
|
||||||
WHEN o.date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
|
CASE WHEN o.date >= dr.current_start
|
||||||
THEN o.quantity * o.price
|
THEN o.quantity * o.price
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END) as current_period_sales,
|
END
|
||||||
SUM(CASE
|
), 0) as current_period_sales,
|
||||||
WHEN o.date BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 60 DAY) AND DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
|
COALESCE(SUM(
|
||||||
|
CASE WHEN o.date >= dr.previous_start AND o.date < dr.current_start
|
||||||
THEN o.quantity * o.price
|
THEN o.quantity * o.price
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END) as previous_period_sales
|
END
|
||||||
|
), 0) as previous_period_sales
|
||||||
FROM products p
|
FROM products p
|
||||||
FORCE INDEX (idx_brand)
|
FORCE INDEX (idx_brand)
|
||||||
INNER JOIN orders o FORCE INDEX (idx_orders_metrics) ON p.pid = o.pid
|
INNER JOIN orders o FORCE INDEX (idx_orders_metrics) ON p.pid = o.pid
|
||||||
AND o.canceled = false
|
CROSS JOIN date_ranges dr
|
||||||
AND o.date >= DATE_SUB(CURRENT_DATE, INTERVAL 60 DAY)
|
|
||||||
AND o.updated > ?
|
|
||||||
WHERE p.brand IN (?)
|
WHERE p.brand IN (?)
|
||||||
|
AND o.canceled = false
|
||||||
|
AND o.date >= dr.previous_start
|
||||||
|
AND o.updated > ?
|
||||||
GROUP BY p.brand
|
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(`
|
await connection.query(`
|
||||||
INSERT INTO brand_metrics (
|
INSERT INTO brand_metrics (
|
||||||
brand,
|
brand,
|
||||||
@@ -199,19 +209,19 @@ async function calculateBrandMetrics(startTime, totalProducts, processedCount =
|
|||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
ps.brand,
|
ps.brand,
|
||||||
COALESCE(ps.product_count, 0) as product_count,
|
ps.product_count,
|
||||||
COALESCE(ps.active_products, 0) as active_products,
|
ps.active_products,
|
||||||
COALESCE(ps.total_stock_units, 0) as total_stock_units,
|
ps.total_stock_units,
|
||||||
COALESCE(ps.total_stock_cost, 0) as total_stock_cost,
|
ps.total_stock_cost,
|
||||||
COALESCE(ps.total_stock_retail, 0) as total_stock_retail,
|
ps.total_stock_retail,
|
||||||
COALESCE(ps.total_revenue, 0) as total_revenue,
|
ps.total_revenue,
|
||||||
COALESCE(ps.avg_margin, 0) as avg_margin,
|
ps.avg_margin,
|
||||||
CASE
|
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 AND COALESCE(ss.current_period_sales, 0) > 0 THEN 100
|
||||||
WHEN COALESCE(ss.previous_period_sales, 0) = 0 THEN 0
|
WHEN COALESCE(ss.previous_period_sales, 0) = 0 THEN 0
|
||||||
ELSE LEAST(999.99, GREATEST(-100,
|
ELSE ROUND(LEAST(999.99, GREATEST(-100,
|
||||||
((COALESCE(ss.current_period_sales, 0) / ss.previous_period_sales) - 1) * 100
|
((ss.current_period_sales / NULLIF(ss.previous_period_sales, 0)) - 1) * 100
|
||||||
))
|
)), 2)
|
||||||
END as growth_rate,
|
END as growth_rate,
|
||||||
NOW() as last_calculated_at
|
NOW() as last_calculated_at
|
||||||
FROM temp_product_stats ps
|
FROM temp_product_stats ps
|
||||||
|
|||||||
@@ -133,52 +133,71 @@ async function calculateCategoryMetrics(startTime, totalProducts, processedCount
|
|||||||
) ENGINE=MEMORY
|
) ENGINE=MEMORY
|
||||||
`);
|
`);
|
||||||
|
|
||||||
// Populate product stats
|
// Populate product stats with optimized index usage
|
||||||
await connection.query(`
|
await connection.query(`
|
||||||
INSERT INTO temp_product_stats
|
INSERT INTO temp_product_stats
|
||||||
SELECT
|
SELECT
|
||||||
c.cat_id,
|
c.cat_id,
|
||||||
COUNT(DISTINCT p.pid) as product_count,
|
COUNT(DISTINCT p.pid) as product_count,
|
||||||
COUNT(DISTINCT CASE WHEN p.visible = true THEN p.pid END) as active_products,
|
COUNT(DISTINCT CASE WHEN p.visible = true THEN p.pid END) as active_products,
|
||||||
SUM(p.stock_quantity * p.cost_price) as total_value,
|
COALESCE(SUM(p.stock_quantity * p.cost_price), 0) as total_value,
|
||||||
AVG(pm.avg_margin_percent) as avg_margin,
|
COALESCE(AVG(NULLIF(pm.avg_margin_percent, 0)), 0) as avg_margin,
|
||||||
AVG(pm.turnover_rate) as turnover_rate
|
COALESCE(AVG(NULLIF(pm.turnover_rate, 0)), 0) as turnover_rate
|
||||||
FROM categories c
|
FROM categories c
|
||||||
FORCE INDEX (PRIMARY)
|
FORCE INDEX (PRIMARY)
|
||||||
JOIN product_categories pc FORCE INDEX (idx_category) ON c.cat_id = pc.cat_id
|
INNER JOIN product_categories pc FORCE INDEX (idx_category) ON c.cat_id = pc.cat_id
|
||||||
LEFT JOIN products p FORCE INDEX (PRIMARY) ON pc.pid = p.pid
|
LEFT JOIN products p FORCE INDEX (PRIMARY) ON pc.pid = p.pid
|
||||||
LEFT JOIN product_metrics pm FORCE INDEX (PRIMARY) ON p.pid = pm.pid
|
LEFT JOIN product_metrics pm FORCE INDEX (PRIMARY) ON p.pid = pm.pid
|
||||||
WHERE c.cat_id IN (?)
|
WHERE c.cat_id IN (?)
|
||||||
|
AND (
|
||||||
|
p.updated > ?
|
||||||
|
OR EXISTS (
|
||||||
|
SELECT 1 FROM orders o FORCE INDEX (idx_orders_metrics)
|
||||||
|
WHERE o.pid = p.pid
|
||||||
|
AND o.updated > ?
|
||||||
|
)
|
||||||
|
)
|
||||||
GROUP BY c.cat_id
|
GROUP BY c.cat_id
|
||||||
`, [batch.map(row => row.cat_id)]);
|
`, [batch.map(row => row.cat_id), lastCalculationTime, lastCalculationTime]);
|
||||||
|
|
||||||
// Populate sales stats
|
// Populate sales stats with optimized date handling
|
||||||
await connection.query(`
|
await connection.query(`
|
||||||
INSERT INTO temp_sales_stats
|
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
|
SELECT
|
||||||
c.cat_id,
|
c.cat_id,
|
||||||
COALESCE(SUM(CASE
|
COALESCE(SUM(
|
||||||
WHEN o.date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
|
CASE WHEN o.date >= dr.current_start
|
||||||
THEN o.quantity * o.price
|
THEN o.quantity * o.price
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END), 0) as recent_revenue,
|
END
|
||||||
COALESCE(SUM(CASE
|
), 0) as recent_revenue,
|
||||||
WHEN o.date BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 60 DAY) AND DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
|
COALESCE(SUM(
|
||||||
|
CASE WHEN o.date >= dr.previous_start AND o.date < dr.current_start
|
||||||
THEN o.quantity * o.price
|
THEN o.quantity * o.price
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END), 0) as previous_revenue
|
END
|
||||||
|
), 0) as previous_revenue
|
||||||
FROM categories c
|
FROM categories c
|
||||||
FORCE INDEX (PRIMARY)
|
FORCE INDEX (PRIMARY)
|
||||||
JOIN product_categories pc FORCE INDEX (idx_category) ON c.cat_id = pc.cat_id
|
INNER JOIN product_categories pc FORCE INDEX (idx_category) ON c.cat_id = pc.cat_id
|
||||||
LEFT JOIN products p FORCE INDEX (PRIMARY) ON pc.pid = p.pid
|
INNER JOIN products p FORCE INDEX (PRIMARY) ON pc.pid = p.pid
|
||||||
LEFT JOIN orders o FORCE INDEX (idx_orders_metrics) ON p.pid = o.pid
|
INNER JOIN orders o FORCE INDEX (idx_orders_metrics) ON p.pid = o.pid
|
||||||
AND o.canceled = false
|
CROSS JOIN date_ranges dr
|
||||||
AND o.date >= DATE_SUB(CURRENT_DATE, INTERVAL 60 DAY)
|
|
||||||
WHERE c.cat_id IN (?)
|
WHERE c.cat_id IN (?)
|
||||||
|
AND o.canceled = false
|
||||||
|
AND o.date >= dr.previous_start
|
||||||
|
AND o.updated > ?
|
||||||
GROUP BY c.cat_id
|
GROUP BY c.cat_id
|
||||||
`, [batch.map(row => row.cat_id)]);
|
`, [batch.map(row => row.cat_id), lastCalculationTime]);
|
||||||
|
|
||||||
// Update metrics using temp tables
|
// Update metrics using temp tables with optimized calculations
|
||||||
await connection.query(`
|
await connection.query(`
|
||||||
INSERT INTO category_metrics (
|
INSERT INTO category_metrics (
|
||||||
category_id,
|
category_id,
|
||||||
@@ -193,17 +212,17 @@ async function calculateCategoryMetrics(startTime, totalProducts, processedCount
|
|||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
c.cat_id,
|
c.cat_id,
|
||||||
COALESCE(ps.product_count, 0) as product_count,
|
ps.product_count,
|
||||||
COALESCE(ps.active_products, 0) as active_products,
|
ps.active_products,
|
||||||
COALESCE(ps.total_value, 0) as total_value,
|
ps.total_value,
|
||||||
COALESCE(ps.avg_margin, 0) as avg_margin,
|
ps.avg_margin,
|
||||||
COALESCE(ps.turnover_rate, 0) as turnover_rate,
|
ps.turnover_rate,
|
||||||
CASE
|
CASE
|
||||||
WHEN ss.previous_revenue = 0 AND ss.recent_revenue > 0 THEN 100
|
WHEN COALESCE(ss.previous_revenue, 0) = 0 AND COALESCE(ss.recent_revenue, 0) > 0 THEN 100
|
||||||
WHEN ss.previous_revenue = 0 THEN 0
|
WHEN COALESCE(ss.previous_revenue, 0) = 0 THEN 0
|
||||||
ELSE LEAST(999.99, GREATEST(-100,
|
ELSE ROUND(LEAST(999.99, GREATEST(-100,
|
||||||
((ss.recent_revenue / NULLIF(ss.previous_revenue, 0) - 1) * 100)
|
((ss.recent_revenue / NULLIF(ss.previous_revenue, 0)) - 1) * 100
|
||||||
))
|
)), 2)
|
||||||
END as growth_rate,
|
END as growth_rate,
|
||||||
c.status,
|
c.status,
|
||||||
NOW() as last_calculated_at
|
NOW() as last_calculated_at
|
||||||
|
|||||||
Reference in New Issue
Block a user