← Back to Database and Storage

Time-Series Database (TSDB) in 20 Lines

Time-series database structure for timestamped writes, tags, retention, and queries.

Database and StorageDatabaseTimeseries

A time-series database is a database built for facts that arrive over time and are usually queried by time range. That sounds simple, but it changes almost every storage decision. The common workload is not a user editing a single business record. It is a stream of measurements such as CPU usage, request latency, stock ticks, sensor readings, or click events arriving continuously and then being aggregated over windows.

The data model is built around measurements, tags, fields, and time

Most TSDBs expose a logical shape that looks close to a table, but internally they are tuned for append-heavy writes and time-based scans.

A common model looks like this:

  • measurement: the metric family, such as cpu or weather
  • tags: indexed dimensions used for filtering, such as host=api-3 or city=Berlin
  • fields: the recorded values, such as usage=71.2 or temperature=18.4
  • timestamp: when the sample was observed

That distinction between tags and fields matters. Tags are usually indexed because they are used to narrow queries. Fields are often stored more compactly because they are the values being aggregated. If you index everything, write throughput and storage cost suffer. If you index too little, analytical queries turn into long scans.

Why TSDBs behave differently from relational databases

Relational databases can store time-series data, and for modest volumes they often should. The difference appears when ingestion rate, retention period, and query shape become dominated by time.

A TSDB typically optimises for three things:

1. High write throughput

Time-series workloads are usually append-only. New samples arrive much more often than old samples are updated. TSDBs exploit this by writing sequentially, buffering in memory, and flushing to immutable segments or log-structured files. That reduces random write cost.

2. Efficient compression

Consecutive timestamps, counters, and slowly changing values compress very well. Many TSDBs use delta encoding, run-length encoding, or column-oriented compression techniques so that long metric histories consume much less space than a naïve row store.

3. Fast time-window queries

Most queries ask for a recent range and then aggregate by time bucket, tag, or both. Examples include average CPU over the last hour, p99 latency by region for the last day, or error count grouped by service. TSDB engines are tuned for this pattern, often with partitioning by time and precomputed metadata that lets the engine skip irrelevant blocks quickly.

Operational features matter as much as raw storage

In practice, TSDB value comes from the surrounding lifecycle controls.

Retention policies

Not all historical data is equally valuable. High-resolution samples may be useful for a week, hourly rollups for a month, and daily summaries for a year. Good TSDBs let you expire or tier old data automatically instead of carrying full-fidelity raw samples forever.

Downsampling and rollups

As data ages, systems often store coarser aggregates. That reduces storage cost and keeps long-range queries usable. The trade-off is that you lose fine-grained detail, so incident forensics may need access to the short-retention raw series.

Cardinality control

This is one of the main failure modes. A tag set with huge uniqueness, such as user_id or raw request path, can explode the number of series. Query performance, memory usage, and index size all degrade. TSDBs reward careful dimensional modelling more than casual schema growth.

When to use a TSDB and when not to

A TSDB is a strong fit for:

  • infrastructure and application metrics
  • observability and monitoring data
  • IoT and sensor telemetry
  • financial ticks and market feeds
  • event streams analysed primarily by time range

It is a poor fit when the workload needs complex joins, frequent updates to historical records, or rich transactional guarantees across many entity types. Those remain better served by relational systems.

The practical rule is simple. Use a TSDB when time is the dominant access pattern and the write path looks like a stream. Use a general-purpose database when time is only one column among many.