Skip to main content

There is a predictable moment in the life of every growing product. The dashboard that used to load in under a second starts taking eleven. Someone opens the reporting page during a board meeting and watches a spinner. Within a fortnight, a proposal lands recommending a cloud data warehouse, an ETL tool, and a data engineer to run both.

Sometimes that proposal is right. Far more often, in our experience, it is an expensive answer to a question nobody actually diagnosed. The dashboard is not slow because the company has outgrown PostgreSQL. It is slow because a row-oriented database is being asked to do a column-oriented job, and in 2026 there are four cheaper rungs on the ladder before you get to Snowflake.

TL;DR

  • Slow dashboards are usually a storage-model problem, not a data-volume problem: row storage reads every column to answer a query that needs three.
  • PostgreSQL got serious columnar options in the last eighteen months. pg_duckdb hit 1.0 with over a million downloads, and pg_mooncake pushed Postgres into the ClickBench top ten, territory previously owned by specialist analytical engines.
  • Most analytical queries scan well under a gigabyte. Below roughly 5TB, a single well-configured machine usually beats a distributed cluster on both cost and latency.
  • The real cost of a warehouse is not the licence, it is the permanent ETL pipeline, the second source of truth, and the freshness lag that comes with both.
  • Escalate in order: fix the query, add a replica, pre-aggregate, add columnar storage, and only then buy a warehouse.

Why the dashboard is actually slow

PostgreSQL stores data in rows. That is exactly what you want for the workload it was designed around: fetch this customer, update that order, insert this event. The engine finds a row and reads it whole.

Analytics inverts the access pattern. A query like “total revenue by month for the last two years” touches three columns across several million rows. Row storage still has to pull every column of every row it scans, including the JSON blob nobody has looked at since 2023. You are paying I/O and memory bandwidth for data the query never uses. The executor then processes those rows one at a time, a function call per row per operator, which was a sound decision in the 1980s when disks were the bottleneck and a poor one now that datasets routinely fit in RAM.

This is why adding an index often does not help. The query is not looking for a needle. It is aggregating the whole haystack, and the storage layout means it reads three times more hay than necessary.

Understanding this matters commercially, because the fix depends entirely on the diagnosis. Data volume problems need distributed systems. Storage layout problems need columnar storage. They cost very different amounts.

What changed in Postgres

For years the honest advice was that if you needed real analytical performance, you left Postgres. That advice is now out of date.

pg_duckdb embeds DuckDB’s vectorised columnar engine directly inside PostgreSQL. It reached version 1.0, passed a million downloads, and became one of the fastest-growing projects in the DuckDB ecosystem. A Microsoft engineer demonstrated it on Azure Database for PostgreSQL Flexible Server running TPC-H queries two to seven times faster, enabled with a single session flag. It reads Parquet directly from object storage, so you can join a live Postgres table against a Parquet dataset in one statement with no pipeline in between.

pg_mooncake takes a different route: it maintains a columnstore mirror of your Postgres tables in Apache Iceberg format with sub-second freshness. That combination pushed PostgreSQL into the ClickBench top ten, a leaderboard normally dominated by purpose-built analytical databases.

TimescaleDB’s Hypercore is the most operationally boring option, which is a compliment. New data lands in row storage, optimised for fast inserts. As it cools, it converts automatically to columnar storage with heavy compression. Both are fully ACID and queryable through the same SQL. For time-series and event data, which describes most SaaS analytics, this is often all you need.

Further out, the experimental pgrust project published a detailed account this month of rebuilding the query engine in Rust: batching 1,024 rows per function call, fusing the scan and aggregation operators into a single pass, then applying SIMD vector instructions. Summing 500 million numbers went from roughly 20 seconds to 135 milliseconds, and the project claims a 300x improvement over stock Postgres on ClickBench. Nowhere near production ready, but it shows where the ceiling is, and the ceiling is far higher than most teams assume.

The escalation ladder

Work down this list. Stop at the first rung that solves the problem, and resist the urge to skip ahead because a later rung sounds more impressive in an architecture review.

  1. Read the query plan. A genuinely large share of “we need a warehouse” conversations end at EXPLAIN ANALYZE. Missing index, accidental sequential scan on a join, a subquery the planner cannot flatten. Cost: an afternoon.
  2. Move reporting to a read replica. If the real complaint is that analytics queries are degrading transactional performance, isolate them. Cost: one instance.
  3. Pre-aggregate. Materialised views or rollup tables refreshed on a schedule. If your dashboard shows daily figures, computing them from raw events on every page load is the actual bug. Cost: a day of work, plus a refresh job to own.
  4. Add columnar storage. pg_duckdb, pg_mooncake, or Hypercore, depending on your data shape. Same database, same SQL, same backups, same access control. Cost: an extension and a benchmark.
  5. Buy the warehouse. Now you know what you need it for, which makes it a much better purchase.

When a warehouse is genuinely the right call

Data warehouses are not a scam. There are clear signals that you have actually arrived:

  • Multi-source joins. The moment you need to join production data against Stripe, HubSpot, and your support desk in one query, you need a place where all of that lives. That is a warehouse job and Postgres extensions will not fake it.
  • Non-engineers writing SQL at will. Unpredictable ad hoc queries from across the organisation are a concurrency and blast-radius problem, and warehouses separate storage from compute precisely to absorb it.
  • Scale past single-node comfort. Broadly, past 5TB of hot analytical data the arithmetic starts favouring the cluster.
  • Retention requirements your primary database should not carry. Seven years of immutable event history does not belong in the database serving your checkout.

The cost nobody puts in the proposal

Warehouse pricing gets scrutinised. The pipeline never does, and the pipeline is where the money goes.

Buying a warehouse means committing permanently to an ETL or ELT layer: extraction jobs, transformation models, orchestration, schema drift handling, and a monitoring story for when a silent failure means Tuesday’s numbers are wrong and nobody notices until Thursday. It means a second source of truth with a freshness lag, and every stakeholder question about why two systems disagree lands on your team.

None of that is unmanageable, but it is a standing operational commitment measured in engineer-days per month, and it belongs next to the licence in the budget rather than being discovered afterwards. Vendors in the single-node camp report analytics spend reductions of 70% or more when teams move back off a cluster. Treat vendor figures as marketing, but the direction is real: plenty of SMEs run distributed infrastructure to serve queries that scan less than a gigabyte.

The AI wrinkle

One thing genuinely does change the calculus: AI agents querying your data. Text-to-SQL tools and analytics agents generate queries that are unpredictable in shape, frequently unoptimised, and issued at machine frequency rather than human frequency. Three analysts with tuned dashboards have a very different concurrency profile from the same team once an agent is exploring the schema on their behalf.

If that is on your roadmap, plan for it: a semantic layer so agents query curated views rather than raw tables, query timeouts and cost limits at the connection level, and read isolation so an agent cannot degrade the transactional path. It is a governance problem before it is a capacity problem, and better solved before the agent goes live than after the incident.

What we would do

For most of the SMEs and startups we work with, the honest recommendation is to stay on PostgreSQL for longer than feels sophisticated. Read the plans, isolate reporting on a replica, pre-aggregate what can be pre-aggregated, and reach for a columnar extension when those run out. The 2026 default is to start on one machine and escalate when the evidence demands it, not when the architecture diagram looks thin.

The teams that get this wrong are rarely the ones who waited too long. They are the ones who bought a distributed data platform at eleven seconds of dashboard latency and spent the next year maintaining a pipeline instead of building product.

REPTILEHAUS works with entrepreneurs, management teams, and agencies on exactly these decisions: database architecture, performance diagnosis, DevOps, and AI integration that survives contact with production. If your dashboards have started to crawl and someone has already sent you a warehouse quote, it is worth a second opinion before you sign. Get in touch and we will look at the query plans first.

📷 Photo by İsmail Enes Ayhan on Unsplash