Time-series DB

A database whose whole job is to swallow a firehose of timestamped metrics and answer "what happened between then and now?" fast.

The idea

A general database expects rows you read, update, and delete in any order. Metrics aren't like that: you only append, timestamps only move forward, and queries are nearly always a time range over one metric.

A time-series DB stores points in time-ordered partitions, keeps recent data at full resolution, and downsamples older partitions into rollups (avg / min / max / count). A range query then reads only the partitions that overlap its window — raw if recent, rolled-up if old.

Press play: points ingest, old partitions downsample, then a range query runs.

How it works

The write path is append-only: every point lands in the partition for its hour, in arrival order, which makes ingestion roughly O(1). A background downsampler turns aged partitions into compact rollup buckets and a retention policy expires the rest. The read path resolves a window to a set of partitions and picks raw versus rollup by age.

def insert(metric, ts, value):
    part = partition_for(ts)        # bucket by hour/day
    part.append(ts, value)          # ordered append, O(1)

def downsample(part):               # background job on old partitions
    part.rollup = aggregate(part)   # {min,max,avg,count} per bucket
    part.drop_raw()                 # reclaim disk

def range_query(metric, start, end):
    rows = []
    for part in select_overlapping(start, end):
        rows += part.read(start, end)   # raw if young, rollup if old
    return rows

Cost

OperationCost
InsertO(1) amortised, sequential write
Range queryO(partitions + points read)
Old-data footprintO(buckets) after downsample

The trade-off: downsampling trades resolution for cheap, fast history. You can render months of trend instantly — but per-point detail beyond the raw-retention window is gone.

Watch out for

Worked example

You ingest http.latency_ms tagged by service and region, ~50k points/second. You keep raw for 3 days, then 10-second rollups for 30 days, then 5-minute rollups for a year. An on-call engineer plotting "yesterday's latency for checkout in us-east" reads 10-second rollups — thousands of buckets — not billions of raw points, so the chart paints in well under a second.

Check yourself

Which tag is the dangerous one to add to a metric?