Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
DatabasesJune 24, 20264 min read

Database performance: Using Summary Tables for Heavy Aggregates

Improve database performance by implementing summary tables for complex aggregates. Learn to optimize slow, read-heavy queries with pre-computed data.

databaseperformancesqlpostgresqloptimizationarchitectureMySQLRedis

Last month, our analytics dashboard started timing out during peak hours. We were running a SUM() and COUNT() across a table with 40 million rows, and even with a perfect composite index, the database engine was sweating to keep up.

That’s when we realized that calculating aggregates on the fly for every request is a losing game. If you’re struggling with similar bottlenecks, it’s time to move beyond indexes and look into pre-computing your data.

The Problem with Real-Time Aggregation

We first tried to optimize the query using standard B-tree indexes. While that helped for small date ranges, the moment a user requested a year-to-date report, the query execution time jumped from 150ms to nearly 4 seconds. The database was performing a massive index scan, and the I/O pressure was killing our connection pool.

Before jumping straight into Materialized views for database performance in complex analytical queries, we looked at the query plan. It was clear: the engine wasn't just reading data; it was doing heavy computation on millions of rows every single time a developer hit "refresh."

Implementing Summary Tables

Instead of forcing the database to work so hard, we shifted to a strategy of pre-computation. A summary table (or aggregate table) acts as a snapshot of your raw data at a specific granularity.

If you have a sales table, you don't need to sum every transaction for the last three years just to show a daily revenue graph. You create a daily_sales_summary table:

SQL
CREATE TABLE daily_sales_summary (
    report_date DATE PRIMARY KEY,
    total_revenue DECIMAL(12, 2),
    transaction_count INT,
    updated_at TIMESTAMP
);

By keeping this table updated, your read queries become trivial SELECT * FROM daily_sales_summary WHERE report_date BETWEEN .... The database performance gains are immediate because you're reading a few rows instead of scanning millions.

Strategies for Maintaining Data Integrity

The biggest trade-off with summary tables is data staleness. You have to decide how "real-time" your data needs to be. We’ve used three different patterns for this:

  1. Trigger-based updates: Best for small datasets. Every INSERT on the source table triggers an UPDATE on the summary table.
  2. Scheduled batch jobs: Best for high-write volumes. A cron job runs every 10 minutes to calculate the delta and update the summary table.
  3. Event-driven aggregation: The most robust method. Using a message queue, we process transactions as they arrive and increment the summary table counters.

If you're already using an event-driven architecture, consider the approach discussed in Database performance: Asynchronous Materialized Views for High-Load Reads. It allows you to decouple your write-heavy ingestion from your read-heavy analytics.

When to Avoid Summary Tables

Don't treat this as a silver bullet for data aggregation. If your business requirement demands sub-second accuracy for every single transaction, summary tables might introduce too much complexity. You’ll end up fighting race conditions and eventual consistency issues.

We once tried to implement this for a real-time fraud detection system. It was a mistake. The lag between the transaction and the aggregate update was about 2 seconds, which was long enough for a malicious actor to drain a balance. For that specific use case, we had to stick to direct queries and Database performance: Adaptive Throttling to Prevent Pool Exhaustion to keep the system stable.

Best Practices for Query Optimization

When you do implement summary tables, keep these tips in mind:

  • Granularity matters: Don't just aggregate by day if you occasionally need hour-by-hour data. You might need multiple summary tables for different time scales.
  • Indexing the summary: Even though the table is small, index the columns you filter by (like report_date).
  • TTL and Archiving: If you're building summaries, make sure you have a plan to prune old data. You don't want your summary table to eventually become as large as your source table.

FAQ

Q: Do summary tables replace indexes? A: No. They complement them. You still need indexes on your raw data for transactional integrity and specific lookups.

Q: How do I handle backfilling historical data? A: Write a migration script that aggregates your existing records into the new summary table. Run it in chunks to avoid locking your main table for too long.

Q: Is this the same as a Materialized View? A: Conceptually, yes. A Materialized View is essentially a managed summary table. Manual summary tables give you more control over the update frequency and indexing strategy.

Final Thoughts

We’ve found that the best approach to query optimization is to stop asking the database to calculate things it has already seen. By shifting the burden of computation to the write-path or a background process, we've kept our dashboards fast even as our data grows.

Next time, I’m planning to experiment with partial indexes to see if we can get similar performance gains without the overhead of maintaining a secondary table. It’s always a balance between storage, complexity, and speed.

Back to Blog

Similar Posts

DatabasesJune 22, 20264 min read

Database performance: Using functional indexes for faster queries

Improve database performance by implementing functional indexes. Learn how to optimize case-insensitive searches and complex filters without bloating your schema.

Read more
Scrabble tiles spelling 'DATA' on a wooden table with a blurred plant background.
DatabasesJune 20, 2026
4 min read

Killing N+1 queries at the database layer: A practical guide

Killing N+1 queries at the database layer is the fastest way to stabilize your app. Learn how to identify, debug, and eliminate performance-killing bottlenecks.

Read more
Close-up of a smartphone showing Python code on the display, showcasing coding and technology.
DatabasesJune 20, 20264 min read

Indexing Strategy for App Developers: Stop Slow Queries

Master an indexing strategy for app developers to fix slow production queries. Learn how to read EXPLAIN plans, pick the right columns, and avoid overhead.

Read more