<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/i-ve-been-using-postgres-wrong-this-whole-time--photqtrh6" -->

---
title: I've been using Postgres wrong this whole time...
description: Vanilla PostgreSQL struggles with high-frequency time series workloads due to the 'B-tree cliff' — when indexes grow too large for RAM, write throughput can...
canonical: https://daily.dev/posts/i-ve-been-using-postgres-wrong-this-whole-time--photqtrh6
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: I've been using Postgres wrong this whole time... | daily.dev
og:description: Vanilla PostgreSQL struggles with high-frequency time series workloads due to the 'B-tree cliff' — when indexes grow too large for RAM, write throughput can...
og:url: https://daily.dev/posts/i-ve-been-using-postgres-wrong-this-whole-time--photqtrh6
og:image: https://api.daily.dev/og/posts/pHOTQtrH6.png
og:image:alt: I've been using Postgres wrong this whole time...
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# I've been using Postgres wrong this whole time...

**[The Coding Gopher](https://daily.dev/sources/codinggopher)** · 9 min read · 19 upvotes · 2 comments

## Summary

Vanilla PostgreSQL struggles with high-frequency time series workloads due to the 'B-tree cliff' — when indexes grow too large for RAM, write throughput can collapse from 100,000 inserts/second to around 500. TimescaleDB, a Postgres extension, solves this through hypertables (automatic time-based partitioning that keeps active indexes RAM-resident), hybrid row-columnar compression (achieving over 90% size reduction using Gorilla, delta-of-delta, and dictionary algorithms), continuous aggregates (incremental materialized views that stitch precomputed history with live data), and over 200 hyperfunctions written in Rust — including HyperLogLog for approximate distinct counts using just 1.5–12 KB of memory with 0.81–2% error rate. The verdict: use vanilla Postgres for CRUD apps, switch to TimescaleDB for observability, IoT, or financial market data workloads.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.youtube.com/watch?v=QyHE6nEgqns>

## Questions this post answers

### Why does Postgres performance collapse when ingesting millions of high-frequency sensor readings?

Write throughput collapses because the B-tree index used for inserts grows too large to fit in RAM as the table reaches hundreds of millions of rows, forcing the operating system to swap memory pages to disk. This 'B-tree cliff' can drop write throughput from 100,000 inserts per second to around 500, turning millisecond queries into multi-minute operations.

_Anyone hitting write bottlenecks with time series data can find deeper Postgres scaling breakdowns on daily.dev._

### How does TimescaleDB avoid the Postgres B-tree cliff for time series data?

TimescaleDB uses hypertables, which automatically partition data into smaller time-based chunks (such as by day or week) built on Postgres declarative partitioning. Since writes are chronological, heavy write traffic only touches the latest chunk, keeping its B-tree index small enough to stay in RAM, while chunk exclusion lets queries prune irrelevant chunks based on timestamp ranges.

_Engineers comparing time series database options can track architecture deep dives like this on daily.dev._

### How much storage can TimescaleDB's columnar compression save on time series data?

Columnar compression routinely shrinks time series data footprint by over 90%, so a terabyte of raw logs can condense to under 100 GB. Recent chunks stay in row format for fast writes, then a background worker converts read-only chunks to columnar format using techniques like Gorilla compression for floats and delta-of-delta encoding for timestamps.

_Teams evaluating storage costs for time series data can follow comparisons like this on daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@trevorsuna** · 1 upvotes

> Hypertables solve a very real index-locality problem, but the rule of thumb matters: vanilla Postgres is still the simpler choice for normal CRUD. The best signal to move is sustained time-series volume and retention pressure, not just the fact that the data has timestamps.

**@agustinbarrientos** · 0 upvotes

> Late writes should join the chunk-size benchmark

## Similar posts on daily.dev

- [You can outgrow vanilla Postgres without abandoning Postgres](https://daily.dev/posts/you-can-outgrow-vanilla-postgres-without-abandoning-postgres-inzvfgbdt) · The New Stack · 2 upvotes · 0 comments
- [How to Query Billion\+ Rows on Postgres Without the Overhead](https://daily.dev/posts/how-to-query-billion-rows-on-postgres-without-the-overhead-icht0tis9) · Daily Dose of Data Science \| Avi Chawla \| Substack · 4 upvotes · 0 comments

---

Tags: [#data-science](https://daily.dev/tags/data-science), [#database](https://daily.dev/tags/database), [#postgresql](https://daily.dev/tags/postgresql), [#timescaledb](https://daily.dev/tags/timescaledb)

[View this post on daily.dev](https://daily.dev/posts/i-ve-been-using-postgres-wrong-this-whole-time--photqtrh6)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"I've been using Postgres wrong this whole time...","url":"https://daily.dev/posts/i-ve-been-using-postgres-wrong-this-whole-time--photqtrh6","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/i-ve-been-using-postgres-wrong-this-whole-time--photqtrh6"},"datePublished":"2026-08-11T16:04:13.046Z","dateModified":"2026-09-13T20:33:43.962Z","description":"Vanilla PostgreSQL struggles with high-frequency time series workloads due to the 'B-tree cliff' — when indexes grow too large for RAM, write throughput can...","image":"https://i.ytimg.com/vi/QyHE6nEgqns/sddefault.jpg","thumbnailUrl":"https://i.ytimg.com/vi/QyHE6nEgqns/sddefault.jpg","isAccessibleForFree":true,"articleSection":"The Coding Gopher","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"The Coding Gopher","logo":"https://media.daily.dev/image/upload/s--pv2IKQMG--/f_auto/v1736753456/logos/codinggopher","url":"https://daily.dev/sources/codinggopher"},"commentCount":2,"discussionUrl":"https://daily.dev/posts/i-ve-been-using-postgres-wrong-this-whole-time--photqtrh6","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":19},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":2}],"keywords":"data-science,database,postgresql,timescaledb","timeRequired":"PT9M","video":{"@type":"VideoObject","name":"I've been using Postgres wrong this whole time...","description":"Vanilla PostgreSQL struggles with high-frequency time series workloads due to the 'B-tree cliff' — when indexes grow too large for RAM, write throughput can...","thumbnailUrl":"https://i.ytimg.com/vi/QyHE6nEgqns/sddefault.jpg","uploadDate":"2026-08-11T16:04:13.046Z","duration":"PT9M","url":"https://api.daily.dev/r/pHOTQtrH6","embedUrl":"https://www.youtube.com/embed/QyHE6nEgqns"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"The Coding Gopher","item":"https://daily.dev/sources/codinggopher"},{"@type":"ListItem","position":3,"name":"I've been using Postgres wrong this whole time..."}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/i-ve-been-using-postgres-wrong-this-whole-time--photqtrh6","comment":[{"@type":"Comment","text":"Hypertables solve a very real index-locality problem, but the rule of thumb matters: vanilla Postgres is still the simpler choice for normal CRUD. The best signal to move is sustained time-series volume and retention pressure, not just the fact that the data has timestamps.","datePublished":"2026-08-15T02:53:57.776Z","url":"https://daily.dev/posts/pHOTQtrH6#c-AWQoHyOBD","author":{"@type":"Person","name":"Trevor Suna","url":"https://daily.dev/trevorsuna","image":"https://media.daily.dev/image/upload/s--dZ7gXxpp--/f_auto/v1784081551/avatars/avatar_EMoP47rpuw8DNjhp6R1b6?_a=BAMAMicg0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1}},{"@type":"Comment","text":"Late writes should join the chunk-size benchmark","datePublished":"2026-08-21T05:58:44.160Z","url":"https://daily.dev/posts/pHOTQtrH6#c-46gjAD6Fx","author":{"@type":"Person","name":"Agustin Barrientos","url":"https://daily.dev/agustinbarrientos","image":"https://media.daily.dev/image/upload/s--5ayxQnqn--/f_auto/v1788281802/avatars/avatar_wQYYVe5Tbj0NJ7C7qPoa8?_a=BAMAMicg0"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/i-ve-been-using-postgres-wrong-this-whole-time--photqtrh6#faq","mainEntity":[{"@type":"Question","name":"Why does Postgres performance collapse when ingesting millions of high-frequency sensor readings?","acceptedAnswer":{"@type":"Answer","text":"Write throughput collapses because the B-tree index used for inserts grows too large to fit in RAM as the table reaches hundreds of millions of rows, forcing the operating system to swap memory pages to disk. This 'B-tree cliff' can drop write throughput from 100,000 inserts per second to around 500, turning millisecond queries into multi-minute operations. Anyone hitting write bottlenecks with time series data can find deeper Postgres scaling breakdowns on daily.dev."}},{"@type":"Question","name":"How does TimescaleDB avoid the Postgres B-tree cliff for time series data?","acceptedAnswer":{"@type":"Answer","text":"TimescaleDB uses hypertables, which automatically partition data into smaller time-based chunks (such as by day or week) built on Postgres declarative partitioning. Since writes are chronological, heavy write traffic only touches the latest chunk, keeping its B-tree index small enough to stay in RAM, while chunk exclusion lets queries prune irrelevant chunks based on timestamp ranges. Engineers comparing time series database options can track architecture deep dives like this on daily.dev."}},{"@type":"Question","name":"How much storage can TimescaleDB's columnar compression save on time series data?","acceptedAnswer":{"@type":"Answer","text":"Columnar compression routinely shrinks time series data footprint by over 90%, so a terabyte of raw logs can condense to under 100 GB. Recent chunks stay in row format for fast writes, then a background worker converts read-only chunks to columnar format using techniques like Gorilla compression for floats and delta-of-delta encoding for timestamps. Teams evaluating storage costs for time series data can follow comparisons like this on daily.dev."}}]}
```

