Time-Series Databases Explained
A time-series database is optimized for timestamped data — metrics, sensor readings, prices. How it differs from general-purpose databases.
A time-series database is a database engine built specifically to store and query data points indexed by time — metrics, sensor readings, application logs, financial ticks — at a scale and query pattern that general-purpose databases handle poorly. The defining trait of time-series data is that it’s overwhelmingly append-only (new points arrive constantly, old ones almost never change) and almost always queried by time range, which lets a purpose-built engine make very different tradeoffs than a general row store.
What makes time-series workloads different
A typical time-series workload has a shape a general-purpose OLTP database isn’t optimized for:
- Write-heavy, append-only. Millions of new points per second is normal — a fleet of servers reporting CPU metrics every ten seconds, or a sensor network. Updates to existing rows are rare to nonexistent.
- Time-range queries dominate. “Give me CPU usage for this host over the last hour” or “average latency per minute for the last day” — almost every query filters and often aggregates by time.
- High cardinality, short retention per point. Individual data points are small and numerous, and old ones are frequently downsampled or deleted entirely once they age past a retention window.
- Aggregation over storage. Nobody usually wants the raw fifteen-million-point series back — they want it summarized: min, max, average, percentiles, bucketed by time interval.
Cramming this into a general-purpose relational table works at small scale, but a naive WHERE timestamp BETWEEN query against a huge unpartitioned table degrades fast, and storing every raw point at full precision forever becomes expensive quickly.
How time-series databases solve it
Time-based partitioning. Data is automatically partitioned into chunks by time range — internally, this looks a lot like database partitioning, applied specifically along the time axis. Old chunks can be compressed, downsampled, or dropped as a unit instead of deleted row-by-row, which is far cheaper.
Columnar or column-like storage. Because queries typically pull one or a few metric columns over a time range rather than whole rows, many time-series engines borrow ideas from columnar storage — values for the same metric compress well together since they tend to be similar or monotonic, and scanning one column doesn’t require reading unrelated ones.
Built-in downsampling and retention policies. Rather than an application job that periodically aggregates and prunes old data, this is a first-class feature: keep raw data for a week, 1-minute averages for a month, hourly averages forever, with the database managing the rollups automatically.
Time-bucketed aggregation functions. Query languages typically have native syntax for “group by 5-minute buckets” that would otherwise require verbose GROUP BY expressions with manual timestamp truncation in a general-purpose SQL database.
When you actually need one
Not every timestamped table needs a specialized database. A created_at column and an index handle plenty of workloads fine in Postgres or MySQL. The signal that you’ve outgrown that is usually scale and query shape together: you’re writing at high, sustained volume, your queries are almost exclusively time-range aggregations, and you’re managing retention and downsampling by hand with cron jobs and DELETE statements that are starting to hurt.
Common real-world use cases: infrastructure and application metrics (the canonical case — CPU, memory, request latency dashboards), IoT and sensor telemetry, financial tick data, and application-level event/analytics pipelines where the query pattern is fundamentally “aggregate over a time window.”
Time-series vs general-purpose databases
| General-purpose (OLTP) | Time-series | |
|---|---|---|
| Optimized for | Point reads/writes, transactions | High-volume appends, time-range scans |
| Typical query | Lookup by ID, joins | Aggregate over a time window |
| Retention handling | Manual deletes/archival jobs | Built-in retention policies, auto-downsampling |
| Storage layout | Row-oriented (usually) | Time-partitioned, often columnar |
| Update pattern | Frequent updates expected | Append-only; updates rare |
A note on extensions vs standalone engines
Some time-series capability comes as an extension to an existing database rather than a separate system — adding time-partitioning, compression, and continuous aggregation to Postgres, for instance. This is often the pragmatic choice: you keep your existing tooling, connection pooling, and operational knowledge, and get most of the time-series wins without running a second database system. Standalone time-series engines tend to win at the very high end of write throughput and long-retention compression, at the cost of one more system to operate and query.
The takeaway
Time-series databases exist because timestamped, append-only, aggregate-heavy data has a shape that general-purpose databases handle inefficiently at scale — they add time-based partitioning, columnar-style storage, and built-in retention and downsampling to match the workload. If your writes are a steady stream of new points and your queries are almost always “aggregate this metric over a time range,” it’s worth evaluating a purpose-built engine — or a time-series extension to whatever you’re already running — well before hand-rolled partitioning and cron-job pruning become a maintenance burden.
Tagged
Keep reading
The Lycoris Team · · 4 min read Data Warehouse vs Data Lake: What's the Difference?
A data warehouse stores structured, pre-modeled data optimized for queries; a data lake stores raw data of any shape. When each one fits.
The Lycoris Team · · 4 min read Star Schema vs Snowflake Schema: Which to Use
Star schema denormalizes dimensions into flat tables for fast queries; snowflake schema normalizes them to save space. How to choose for your warehouse.
The Lycoris Team · · 5 min read What Is a Graph Database?
A graph database stores data as nodes and relationships instead of tables, making deeply connected queries fast instead of a chain of costly joins.