perf: Optimize dashboard queries for faster load times
- Use pg_stat for approximate product count (instant vs full scan) - LIMIT on DISTINCT queries for brand/category counts - Single combined query (reduces round trips) - Add index on store_product_snapshots.captured_at - Add index on worker_tasks.worker_id and created_at 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,63 +14,31 @@ router.use(authMiddleware);
|
||||
/**
|
||||
* GET /api/markets/dashboard
|
||||
* Dashboard summary with counts for dispensaries, products, brands, etc.
|
||||
* Optimized: Uses single query with approximate counts for large tables
|
||||
*/
|
||||
router.get('/dashboard', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Get dispensary count
|
||||
const { rows: dispRows } = await pool.query(
|
||||
`SELECT COUNT(*) as count FROM dispensaries`
|
||||
);
|
||||
|
||||
// Get product count from store_products (canonical) or fallback to dutchie_products
|
||||
const { rows: productRows } = await pool.query(`
|
||||
SELECT COUNT(*) as count FROM store_products
|
||||
`);
|
||||
|
||||
// Get brand count
|
||||
const { rows: brandRows } = await pool.query(`
|
||||
SELECT COUNT(DISTINCT brand_name_raw) as count
|
||||
FROM store_products
|
||||
WHERE brand_name_raw IS NOT NULL
|
||||
`);
|
||||
|
||||
// Get category count
|
||||
const { rows: categoryRows } = await pool.query(`
|
||||
SELECT COUNT(DISTINCT category_raw) as count
|
||||
FROM store_products
|
||||
WHERE category_raw IS NOT NULL
|
||||
`);
|
||||
|
||||
// Get snapshot count in last 24 hours
|
||||
const { rows: snapshotRows } = await pool.query(`
|
||||
SELECT COUNT(*) as count
|
||||
FROM store_product_snapshots
|
||||
WHERE captured_at >= NOW() - INTERVAL '24 hours'
|
||||
`);
|
||||
|
||||
// Get last crawl time
|
||||
const { rows: lastCrawlRows } = await pool.query(`
|
||||
SELECT MAX(completed_at) as last_crawl
|
||||
FROM crawl_orchestration_traces
|
||||
WHERE success = true
|
||||
`);
|
||||
|
||||
// Get failed job count (jobs in last 24h that failed)
|
||||
const { rows: failedRows } = await pool.query(`
|
||||
SELECT COUNT(*) as count
|
||||
FROM crawl_orchestration_traces
|
||||
WHERE success = false
|
||||
AND started_at >= NOW() - INTERVAL '24 hours'
|
||||
// Single optimized query for all counts
|
||||
const { rows } = await pool.query(`
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM dispensaries) as dispensary_count,
|
||||
(SELECT n_live_tup FROM pg_stat_user_tables WHERE relname = 'store_products') as product_count,
|
||||
(SELECT COUNT(*) FROM (SELECT DISTINCT brand_name_raw FROM store_products WHERE brand_name_raw IS NOT NULL LIMIT 10000) b) as brand_count,
|
||||
(SELECT COUNT(*) FROM (SELECT DISTINCT category_raw FROM store_products WHERE category_raw IS NOT NULL LIMIT 1000) c) as category_count,
|
||||
(SELECT COUNT(*) FROM store_product_snapshots WHERE captured_at >= NOW() - INTERVAL '24 hours') as snapshot_count_24h,
|
||||
(SELECT MAX(completed_at) FROM crawl_orchestration_traces WHERE success = true) as last_crawl,
|
||||
(SELECT COUNT(*) FROM crawl_orchestration_traces WHERE success = false AND started_at >= NOW() - INTERVAL '24 hours') as failed_count
|
||||
`);
|
||||
|
||||
const r = rows[0];
|
||||
res.json({
|
||||
dispensaryCount: parseInt(dispRows[0]?.count || '0', 10),
|
||||
productCount: parseInt(productRows[0]?.count || '0', 10),
|
||||
brandCount: parseInt(brandRows[0]?.count || '0', 10),
|
||||
categoryCount: parseInt(categoryRows[0]?.count || '0', 10),
|
||||
snapshotCount24h: parseInt(snapshotRows[0]?.count || '0', 10),
|
||||
lastCrawlTime: lastCrawlRows[0]?.last_crawl || null,
|
||||
failedJobCount: parseInt(failedRows[0]?.count || '0', 10),
|
||||
dispensaryCount: parseInt(r?.dispensary_count || '0', 10),
|
||||
productCount: parseInt(r?.product_count || '0', 10),
|
||||
brandCount: parseInt(r?.brand_count || '0', 10),
|
||||
categoryCount: parseInt(r?.category_count || '0', 10),
|
||||
snapshotCount24h: parseInt(r?.snapshot_count_24h || '0', 10),
|
||||
lastCrawlTime: r?.last_crawl || null,
|
||||
failedJobCount: parseInt(r?.failed_count || '0', 10),
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('[Markets] Error fetching dashboard:', error.message);
|
||||
|
||||
Reference in New Issue
Block a user