CarbonSite
← Back to blog

Carbon Accounting at Scale: Why Your Dashboard Feels Slow

6 min readBy CarbonSite
performancedashboardscaledatabase optimizationanalytics
Carbon Accounting at Scale: Why Your Dashboard Feels Slow

You're a sustainability manager at a mid-market UK firm. You've got 5 facilities, 50 suppliers, 100+ reporting periods worth of data (years of history).

You open your carbon dashboard expecting to see a quick summary. Instead:

  • Loading spinner spins for 20+ seconds
  • Dashboard finally loads, but any filter change takes another 15 seconds
  • Try to export to CSV? 30 second wait
  • Drill into a facility? Another 15 second load time

Your competitors' dashboards load instantly. You wonder: why is yours so slow?

The problem isn't your internet connection. It's your carbon accounting architecture.

Why Most Dashboards Are Slow

Traditional carbon accounting systems calculate emissions on-demand:

  1. User opens dashboard
  2. System queries all activity records for the period
  3. System applies filters (facility, category, date range)
  4. System calculates totals by aggregating millions of rows
  5. System renders results (15-30 seconds later)

This works for small datasets (100-1,000 records). But at scale:

  • 100,000 records? Dashboard takes 10+ seconds
  • 1,000,000 records? Dashboard takes 30+ seconds
  • 10,000,000 records? Dashboard takes minutes or times out

Every filter change, every date range selection, every drill-down requires the system to re-calculate millions of rows. It's like asking an accountant to manually add up a million transactions every time someone asks "what's our profit this quarter?"

The Pre-Calculation Solution

Fast carbon dashboards use pre-calculated aggregates:

1. Define Aggregation Dimensions Instead of calculating on-demand, pre-calculate every possible combination:

  • By Facility (5 facilities)
  • By Category (12 categories)
  • By Month (36 months)
  • By Scope (3 scopes)
  • By Status (4 statuses: draft, approved, rejected, audited)

This creates: 5 × 12 × 36 × 3 × 4 = 25,920 pre-calculated rows

Each row contains:

Facility: Manchester Manufacturing
Category: Waste → Landfill
Month: 2025-03
Scope: 3
Status: Approved
Count: 156
Total CO₂e: 1,500
Total kg: 5,000
Variance: +2.5% (vs. previous month)

2. Store Pre-Calculated Results in Optimized Tables CarbonSite uses materialized views and dedicated aggregate tables:

DashboardAggregate Table (indexed for speed):
- Facility ID (indexed)
- Reporting Period (indexed)
- Scope (indexed)
- Category (indexed)
- Total CO₂e (pre-calculated)
- Total Records (pre-calculated)
- Status (indexed)

Indexes:
- (Facility, Period, Scope) → 100ms query
- (Period, Category) → 50ms query
- (Facility, Period) → 30ms query

3. Refresh Pre-Calculated Results After Each Calculation After a calculation run completes:

  1. Identify affected rows (facility, periods, categories)
  2. Recalculate only those rows (not the entire dataset)
  3. Update the aggregate table
  4. Dashboard reflects new data instantly

Result: Dashboard loads in < 500ms, even with millions of records.

Real Performance Comparison

Example: Dashboard for 10,000 activity records

Traditional on-demand calculation:

User opens dashboard
↓ (System queries 10,000 records)
↓ (System aggregates by facility/category/month)
↓ (System filters and calculates totals)
Load time: 15-25 seconds

CarbonSite pre-calculated approach:

User opens dashboard
↓ (System queries 25 pre-calculated rows)
↓ (System renders results)
Load time: < 500ms

50x faster.

Example: Facility drill-down

Traditional:

User clicks "Manchester Facility"
↓ (System queries all records for this facility: 1,200 records)
↓ (System groups by category and month)
↓ (System calculates trend analysis)
Load time: 8-15 seconds

CarbonSite:

User clicks "Manchester Facility"
↓ (System retrieves 36 pre-calculated rows: one per month)
↓ (System renders timeline chart)
Load time: < 300ms

30x faster.

Incremental Aggregation

Pre-calculating everything is possible for small datasets, but scales poorly. CarbonSite uses incremental aggregation:

Monthly Aggregation:

  • At end of month (or when period closes), calculate final aggregate
  • Store in permanent table
  • This aggregate never changes again (immutable)

Real-Time Aggregation:

  • For in-progress period, maintain running aggregate
  • As new records arrive, increment the aggregate (add 100 tonnes to February total)
  • No need to recalculate millions of rows

Hierarchical Aggregation:

Day-level aggregates (fast trend analysis)
 ↓
Week-level aggregates (fast weekly reporting)
 ↓
Month-level aggregates (historical comparison)
 ↓
Year-level aggregates (annual reporting)

User wants to see "trend over last 12 months"? System queries 12 rows (one per month), not millions.

Real Example: Logistics Network

A UK logistics company with 20 distribution centers, 500 vehicles, 3 years of history had grown to 5 million activity records. Their old system took 45 seconds to load the dashboard.

The problem:

  • Every dashboard load aggregated 5 million records
  • Filter changes (select a facility) re-aggregated the dataset
  • Export to CSV took 2+ minutes
  • Mobile users on poor connections often gave up

With CarbonSite's pre-calculation:

  • Dashboard loads in < 500ms (queries 60 pre-calculated rows)
  • Filter changes load in < 200ms (queries different pre-calculated rows)
  • Export to CSV completes in 2 seconds
  • Mobile performance perfect (low bandwidth)

The result:

  • Users actually use the dashboard (before: checked it once, then gave up)
  • Facility managers can run impromptu analysis
  • Finance team can export reports on demand
  • Executives get real-time visibility into emissions

Database Indexes and Query Optimization

Beyond pre-calculation, CarbonSite optimizes queries with strategic indexes:

For Fast Facility Lookups:
CREATE INDEX idx_activity_facility_period 
  ON ActivityRecord (facility_id, reporting_period_id, created_at)

For Fast Category Aggregation:
CREATE INDEX idx_activity_category_scope 
  ON ActivityRecord (emission_category_id, scope, created_at)

For Fast Status Queries:
CREATE INDEX idx_activity_status_facility 
  ON ActivityRecord (review_status, facility_id, reporting_period_id)

These indexes mean:

  • "Get all records for facility X in period Y" → 50ms (vs. 5 seconds without index)
  • "Sum all Scope 3 emissions in January" → 100ms (vs. 10 seconds)
  • "Count approved records by facility" → 150ms (vs. 30 seconds)

Caching Layer

For queries that don't change often, CarbonSite uses Redis caching:

Query: "Get dashboard totals for facility Manchester, month March 2025"
First load:
  1. Check Redis cache (miss)
  2. Query database (100ms)
  3. Store in Redis cache (expiry: 1 hour)
  4. Return to user (100ms)

Subsequent loads (within 1 hour):
  1. Check Redis cache (hit)
  2. Return from cache (< 1ms)

For a sustainability manager checking the dashboard 50 times a day, 49 of those loads come from cache.

Getting Started with Performance

If your carbon dashboard feels slow:

  • Small dataset (< 10,000 records)? You probably don't need optimization yet
  • Medium dataset (10,000 - 100,000 records)? Pre-calculated aggregates will help
  • Large dataset (> 100,000 records)? Pre-calculation is essential

CarbonSite uses pre-calculation by default:

  • Free Plan: Basic aggregation (up to 10,000 records)
  • Growth Plan: £50/month, advanced pre-calculation, Redis caching
  • Enterprise: Custom optimization, materialized views, time-series optimization

[Experience Fast Carbon Dashboards] or [Compare Performance]

More from the blog

Read all posts →