Keeping years of chain data fast enough for “last 5 minutes” charts
Introduction
Every serious blockchain product ends up needing time‑series analytics.
You want to see TPS over the last hour, gas usage over the last month, swap volume over the last year, liquidity over the lifetime of a pool. All of that is “value at time T” style data, and it behaves very differently from classic transactional tables.(tigerdata.com)
In this article I’ll walk through how I manage time‑series blockchain data using TimescaleDB (PostgreSQL extension) as the core engine, and how I structure aggregation and dashboards so they stay fast even when there are billions of points behind a simple line chart.(GitHub)
What “time‑series” means in blockchain systems
In blockchain work, time‑series data usually falls into a few buckets.
You have protocol‑level metrics like blocks per second, gas used, average fees, mempool depth, validator performance. Then you have product metrics: DEX volume per pair, TVL per pool, user portfolio value over time, liquidation events, bridge flows per chain. They are all “measurement at time T” with two or three dimensions attached (chain, asset, address, pool, validator).(tigerdata.com)
A simple way I frame it:
value = f(time, dimensions...)
where dimensions might be chain_id, metric_name, asset, pool_id, address_class, and so on. Once you see that shape, time‑series tools start to make sense.
Why I like TimescaleDB for blockchain analytics
TimescaleDB is a PostgreSQL extension that turns a normal table into a hypertable: automatically partitioned by time (and optionally a second “space” key) with time‑aware optimisations for ingest and querying. You get high write throughput, partition‑pruning on time ranges, compression, and continuous aggregates, but you still write SQL and keep the full Postgres ecosystem.(GitHub)
Time‑series databases in general are built for three things that match blockchain analytics almost perfectly:
- ingesting a lot of time‑stamped data
- keeping it compressed and prunable over years
- running interval queries and aggregations efficiently over large windows(tigerdata.com)
Timescale gives me those properties without leaving the relational world or setting up a separate TSDB stack.
At a high level it looks like this:
[ Nodes / Indexers ]
|
v
[ TimescaleDB ]
|
+-- hypertable: raw metrics
+-- continuous aggregates: 1m / 1h / 1d rollups
|
v
[ Dashboards / APIs ]
Modelling blockchain metrics as time‑series
For analytics, I usually separate facts from dimensions.
Facts are the actual measurements: TPS, volume, balances, gas used. Dimensions are labels that slice those facts: which chain, which asset, which pool, which kind of address.
In Timescale that becomes one or a small number of hypertables, with columns roughly like:
time – timestamp of the measurement
chain_id – which chain or network
metric – e.g. "tps", "dex_volume_usd", "avg_fee"
value – numeric value
dimension_1 – optional (asset, pool, validator...)
dimension_2 – optional (side, category...)
...
Timescale’s own modelling guides talk about this sort of “narrow” table layout: one measurement per row, dimensions as columns, so you can use normal SQL to filter and group.(tigerdata.com)
The important part is to be explicit about what is a dimension and what is just metadata. Dimensions go into indexed columns; throw‑away metadata can live in a JSONB column if you really need it.
Hypertables and chunking: how Timescale keeps up
A hypertable in TimescaleDB is a logical table that is automatically partitioned into many smaller chunks by time (and optionally a second key). Under the hood, each chunk is a normal Postgres table, but the extension routes inserts and queries to the right chunk and skips the rest.(tigerdata.com)
I visualise it like this:
Logical hypertable: metrics
+-----------------------------------+
| time | chain | metric | value... |
+-----------------------------------+
Physical chunks (by month, for example):
metrics_2025_01 [ Jan 2025 ]
metrics_2025_02 [ Feb 2025 ]
metrics_2025_03 [ Mar 2025 ]
...
When you query “last 7 days of DEX volume”, the planner can skip all older chunks and hit only a handful of physical tables. That is where a lot of the speed comes from at scale.(tigerdata.com)
For indexes I keep it simple: a composite index on (time DESC, metric, chain_id, dimension_1) is usually enough for most queries, and Timescale’s own docs and time‑series Postgres guides recommend exactly this kind of “time plus one or two dimensions” indexing strategy.(Amazon Web Services, Inc.)
Aggregation strategy: raw vs rolled‑up history
Raw blockchain metrics can be very high volume: one point per block per metric across multiple chains turns into billions of rows quickly.
To keep that manageable, I split history into layers:
Fine : per block or per few seconds, recent only
Medium : per minute or per hour, medium horizon
Coarse : per day or per week, full history
A simple ASCII timeline helps:
<------- full chain history ------->
| raw (recent) | only rollups |
| block / 5s | 1m / 1h / 1d |
Time‑series database guides call this pattern downsampling: you keep detailed data for a short period, then aggregate and compress older data into coarser buckets, dropping the raw points when you no longer need that resolution.(DataCamp)
In blockchain analytics that often looks like:
- raw: per block or per swap for the last few weeks
- 1‑minute rollups for the last few months
- 1‑hour or daily rollups for everything older
This keeps dashboards responsive while keeping storage and I/O under control.
Continuous aggregates: pre‑computing dashboards in the database
Downsampling by hand quickly becomes painful. This is where continuous aggregates in TimescaleDB are extremely useful.
Continuous aggregates are incrementally maintained, time‑series‑aware materialised views: you define an aggregate query over a hypertable, and Timescale keeps the result updated in the background, only processing new or changed data instead of recomputing everything.(Medium)
Conceptually:
Hypertable: metrics(time, metric, value, ...)
Continuous aggregate:
SELECT time_bucket('1 minute', time) AS bucket,
chain_id,
metric,
SUM(value) AS value
FROM metrics
GROUP BY bucket, chain_id, metric;
You don’t have to run this yourself; Timescale materialises it and refreshes it for new data. Articles and docs describe continuous aggregates as “high‑performance materialized views that automatically refresh only changed regions”, which is exactly what you want for fast charts over huge datasets.(Medium)
There is also the idea of real‑time aggregates: when you query a continuous aggregate, Timescale transparently stitches the pre‑aggregated part with the freshest raw data that hasn’t been materialised yet. That gives you “up to now” views without waiting for the next refresh.(Tiger Data)
I think of it like this:
[ raw hypertable ] ----> [ continuous aggregate: 1m buckets ]
^ |
| v
"recent data" [ dashboard queries ]
added on the fly
One crucial operational detail: you must define refresh policies for each continuous aggregate so that background jobs actually materialise data. Timescale’s docs and community Q&A call this out directly; without a policy, a continuous aggregate will not automatically fill.(Stack Overflow)
Building real‑time dashboards on top
Once hypertables and continuous aggregates are in place, front‑end dashboards become much simpler.
The architecture I usually end up with looks like this:
[ Nodes / Indexers ]
|
v
[ TimescaleDB ]
|
+-- hypertable: raw metrics
+-- continuous aggregates: 1m / 1h / 1d
|
v
[ API / BFF ]
|
v
[ Dashboards: Grafana / custom React ]
Timescale is that “one database that does both transactions and analytics” for many workloads: you can keep normal Postgres tables for transactional or reference data and hypertables for metrics, avoiding separate ETL into a dedicated TSDB.(Medium)
From the dashboard side, the queries are straightforward: select from the appropriate continuous aggregate with a WHERE time BETWEEN ... filter and whatever dimensions you need. Articles on building SQL dashboards on Timescale underline this pattern: let the database handle bucketting and pre‑aggregation, keep the front‑end thin.(tigerdata.com)
I usually:
- use minute‑level aggregates for “last few hours” graphs
- switch to hourly or daily aggregates for longer ranges
- cache API responses for common views to shield the DB further during spikes
With that in place, you can show “last 5 minutes” charts over years of history without the database breaking a sweat.
Retention, compression, and cost control
Time‑series grows without bound unless you push back.
TimescaleDB supports native compression for older chunks, and retention policies to drop or move old data. Guides on Timescale and generic TSDBs both stress these two knobs as essential: compress what you keep; delete or archive what you no longer need.(tigerdata.com)
In blockchain analytics I tend to adopt a policy like:
- keep raw, uncompressed metrics for the last N days or weeks,
- compress older raw chunks,
- eventually drop raw beyond a horizon once daily rollups exist,
- keep aggregates long term (daily or weekly) for historical charts.
That matches what many TSDB best‑practice posts recommend: short‑term detail, long‑term summary.(DataCamp)
From an operational perspective it also makes backups more predictable and lets you plan storage growth in advance instead of waking up one day with a multi‑terabyte hypertable full of per‑block metrics from three years ago.
Operational and architectural notes
A few practical points I keep in mind when building these pipelines.
I prefer one ingestion path for metrics, not three. The same indexer that parses blocks and pushes transactions into Postgres or Kafka also derives time‑series metrics and inserts them into Timescale. Timescale’s position as a Postgres extension makes it natural to keep it in the same cluster as other relational data, as Cloudflare and others have described.(The Cloudflare Blog)
I watch write throughput and query latency separately. Time‑series guides always remind you that you need both: a TSDB that ingests quickly but responds slowly isn’t useful for dashboards. Hypertables with time‑based partitioning, correct indexes, and continuous aggregates give you healthy numbers on both axes.(tigerdata.com)
And I accept that some analytics live elsewhere. For very heavy, exploratory analytics—“scan all historical swaps and run arbitrary queries”—I usually load continuous aggregates into a warehouse or columnar store. Timescale handles the “online, user‑facing” graphs; the warehouse handles offline crunching.
From the trenches: On one multi‑chain analytics platform, moving from a plain Postgres table with manual partitions to Timescale hypertables plus continuous aggregates cut typical dashboard query times by an order of magnitude and made it realistic to keep years of metrics online instead of constantly archiving them.
Conclusion
Blockchain analytics is almost pure time‑series: numbers and events evolving over time, sliced by a handful of dimensions.
TimescaleDB works well here because it gives you:
- hypertables that partition data by time and keep writes fast
- time‑aware query planning and compression for very large histories
- continuous aggregates and real‑time aggregates that pre‑compute the heavy work and keep dashboards snappy
If you design your schema around time plus a few dimensions, downsample sensibly, and let continuous aggregates do the heavy lifting, you can support “real‑time” dashboards on top of years of multi‑chain history without hauling in a whole second database stack or hand‑rolling every optimisation yourself.
Completion scope and production contract
This completion review turns the earlier conceptual treatment into a release-oriented engineering contract. It treats Time-Series Data Management for Blockchain Analytics as a Kotlin and Spring backend component, follows a request, domain command, event, database transaction, coroutine, or stream record through validation and durable state, and separates normative requirements from implementation policy. The normative baseline is the domain contract, published API schema, database constraints, and framework lifecycle; deployment defaults, caching, retry limits, and operator thresholds are explicitly local policy. 13
The intended audience is experienced developers and architects. Readers should understand the surrounding chain or application model, typed data structures, persistence, and basic security engineering. The scope includes correctness, implementation boundaries, deterministic tests, failure recovery, security, performance, and observability. It does not claim that the educational companion is a drop-in replacement for a maintained protocol or cryptographic library. Production adoption requires an independent threat model, compatibility testing against the authoritative implementation, and operational ownership. 14
The mental model used throughout is deliberately strict: untrusted input crosses HTTP, authentication, messaging, domain, database, and downstream-node boundaries; a validator derives facts under the domain contract, published API schema, database constraints, and framework lifecycle; accepted transitions update transactional domain state plus replayable processing progress; and observers consume committed facts, never optimistic intermediate mutations. A guarantee is stated only when it follows from those rules and assumptions. Heuristics such as fee selection, caching, peer scoring, timeouts, user messaging, or alert thresholds remain policy and may be tuned without redefining validity. 15
Reader contract and scope
For Time-Series Data Management for Blockchain Analytics, this review makes the exact user decision and the prerequisites needed to make it safely explicit. Start from one request, domain command, event, database transaction, coroutine, or stream record and write down its origin, canonical representation, validation context, authority, and durable outcome. The Kotlin and Spring backend component must not infer a stronger fact from transport success, cache presence, or an upstream acknowledgement. Its authoritative state is transactional domain state plus replayable processing progress, and every projection must remain rebuildable or reconcilable from committed facts. This framing distinguishes a protocol guarantee from an operational convenience and gives reviewers a concrete place to challenge an assumption. 13
The principal failure to design against is an attractive example being mistaken for a complete production design. Address it before optimizing by defining a narrow ownership boundary, stable identities, bounded resource use, and a machine-readable outcome for every rejected transition. Record a scope statement, excluded concerns, and a reviewable acceptance criterion. A reviewer should be able to trace each accepted result to input bytes, rule or policy version, prior state, and commit identity without relying on prose logs. When the authority cannot be reached or context is incomplete, return an explicit unavailable or pending state; do not convert uncertainty into acceptance.
Precise vocabulary and authority
Treat precise vocabulary and authority as part of the executable design of Time-Series Data Management for Blockchain Analytics, not as documentation added after coding. The relevant operating envelope includes historical ingestion, bursty APIs, retries, rolling deployment, backfill, and downstream degradation. For each mode, identify which state is authoritative, which work may be retried, what is bounded, and which observation proves progress. This is especially important across HTTP, authentication, messaging, domain, database, and downstream-node boundaries, where delivery and processing are different events and where local time or arrival order may not reflect authoritative order. 14
A useful review asks how the design behaves under lost update, duplicate event, poison record, pool exhaustion, timeout, schema skew, and inconsistent retry. The unsafe outcome is teams using the same word for incompatible states or guarantees. Prevent it with explicit preconditions and postconditions, and retain a glossary tied to the normative authority for every overloaded term as release evidence. Use stable codes rather than exception text, keep policy configuration versioned, and attach the accepted policy or rule version to durable results. An service or data-platform operator must be able to stop intake, drain or quarantine work, compare local state with authority, and resume without inventing a second side effect.
Trust assumptions
The implementation of Time-Series Data Management for Blockchain Analytics should expose which actors, clocks, stores, libraries, and upstream systems may fail or act maliciously through types and module boundaries. Parse external representations once, preserve the original identity when audit or replay needs it, and pass validated domain values inward. Mutations of transactional domain state plus replayable processing progress belong behind one authoritative transition function or transaction boundary. Network clients, storage adapters, user interfaces, and telemetry exporters must not duplicate consensus or business rules. That separation keeps deterministic logic testable and prevents a library upgrade from silently redefining validity. 15
Assume that an implicit trusted component invalidating the claimed guarantee will eventually occur in a staging fault test or production incident. The control is not a catch-all retry: classify the outcome, decide whether the identical operation is safe to repeat, bound attempts and elapsed time, and surface terminal work for reconciliation. The minimum evidence is a trust-boundary diagram and an assumption register with owners. Keep credentials, bearer tokens, signing requests, customer identifiers, and database change history out of ordinary logs, and prefer hashes, version identifiers, counts, and sanitized reason codes. Any emergency bypass must be narrow, time-limited, approved, and observable.
Architecture and ownership
Verification for Time-Series Data Management for Blockchain Analytics must demonstrate component responsibilities and the direction in which facts and commands move at several layers. Small tests cover deterministic transforms and boundary values; contract tests pin serialized forms; integration tests exercise real adapters; replay tests compare state roots or projections; and fault tests interrupt work at every commit boundary. The dataset must include normal history, malformed input, duplicates, reordering, maximum-size values, and changes of rule or schema version. A passing example is evidence about that environment and dataset, not a universal performance claim. 13
Make two components both believing they own the same transition a named negative test. The release packet should retain a context diagram, ownership table, and dependency rule, exact dependency and tool versions, the deterministic command, and its result. For performance work, report warm-up, repetitions, concurrency, percentiles, resource limits, and the point where backpressure begins. For security work, include abuse cases and independent review. A change is ready only when failures leave transactional domain state plus replayable processing progress safe, recovery is rehearsed, and telemetry explains both user-visible outcome and operator action.
Canonical representation
For Time-Series Data Management for Blockchain Analytics, this review makes the byte-level or schema-level representation used for hashing, comparison, storage, and transport explicit. Start from one request, domain command, event, database transaction, coroutine, or stream record and write down its origin, canonical representation, validation context, authority, and durable outcome. The Kotlin and Spring backend component must not infer a stronger fact from transport success, cache presence, or an upstream acknowledgement. Its authoritative state is transactional domain state plus replayable processing progress, and every projection must remain rebuildable or reconcilable from committed facts. This framing distinguishes a protocol guarantee from an operational convenience and gives reviewers a concrete place to challenge an assumption. 14
The principal failure to design against is semantically equal values producing different identifiers or verification outcomes. Address it before optimizing by defining a narrow ownership boundary, stable identities, bounded resource use, and a machine-readable outcome for every rejected transition. Record golden encodings, round-trip tests, and rejection of non-canonical forms. A reviewer should be able to trace each accepted result to input bytes, rule or policy version, prior state, and commit identity without relying on prose logs. When the authority cannot be reached or context is incomplete, return an explicit unavailable or pending state; do not convert uncertainty into acceptance.
State-machine model
Treat state-machine model as part of the executable design of Time-Series Data Management for Blockchain Analytics, not as documentation added after coding. The relevant operating envelope includes historical ingestion, bursty APIs, retries, rolling deployment, backfill, and downstream degradation. For each mode, identify which state is authoritative, which work may be retried, what is bounded, and which observation proves progress. This is especially important across HTTP, authentication, messaging, domain, database, and downstream-node boundaries, where delivery and processing are different events and where local time or arrival order may not reflect authoritative order. 15
A useful review asks how the design behaves under lost update, duplicate event, poison record, pool exhaustion, timeout, schema skew, and inconsistent retry. The unsafe outcome is an impossible intermediate state becoming durable after interruption. Prevent it with explicit preconditions and postconditions, and retain a transition table exercised by positive, negative, and replay tests as release evidence. Use stable codes rather than exception text, keep policy configuration versioned, and attach the accepted policy or rule version to durable results. An service or data-platform operator must be able to stop intake, drain or quarantine work, compare local state with authority, and resume without inventing a second side effect.
Invariants
The implementation of Time-Series Data Management for Blockchain Analytics should expose properties that must hold before and after every accepted operation through types and module boundaries. Parse external representations once, preserve the original identity when audit or replay needs it, and pass validated domain values inward. Mutations of transactional domain state plus replayable processing progress belong behind one authoritative transition function or transaction boundary. Network clients, storage adapters, user interfaces, and telemetry exporters must not duplicate consensus or business rules. That separation keeps deterministic logic testable and prevents a library upgrade from silently redefining validity. 13
Assume that local success concealing corruption in a related aggregate or index will eventually occur in a staging fault test or production incident. The control is not a catch-all retry: classify the outcome, decide whether the identical operation is safe to repeat, bound attempts and elapsed time, and surface terminal work for reconciliation. The minimum evidence is executable assertions at the narrowest authoritative boundary. Keep credentials, bearer tokens, signing requests, customer identifiers, and database change history out of ordinary logs, and prefer hashes, version identifiers, counts, and sanitized reason codes. Any emergency bypass must be narrow, time-limited, approved, and observable.
Validation pipeline
Verification for Time-Series Data Management for Blockchain Analytics must demonstrate cheap structural checks, contextual checks, authoritative verification, and commit order at several layers. Small tests cover deterministic transforms and boundary values; contract tests pin serialized forms; integration tests exercise real adapters; replay tests compare state roots or projections; and fault tests interrupt work at every commit boundary. The dataset must include normal history, malformed input, duplicates, reordering, maximum-size values, and changes of rule or schema version. A passing example is evidence about that environment and dataset, not a universal performance claim. 14
Make expensive or stateful work running before malformed input is rejected a named negative test. The release packet should retain ordered validation stages with stable machine-readable rejection codes, exact dependency and tool versions, the deterministic command, and its result. For performance work, report warm-up, repetitions, concurrency, percentiles, resource limits, and the point where backpressure begins. For security work, include abuse cases and independent review. A change is ready only when failures leave transactional domain state plus replayable processing progress safe, recovery is rehearsed, and telemetry explains both user-visible outcome and operator action.
Error semantics
For Time-Series Data Management for Blockchain Analytics, this review makes the distinction between invalid input, conflict, unavailable dependency, retryable interruption, and internal defect explicit. Start from one request, domain command, event, database transaction, coroutine, or stream record and write down its origin, canonical representation, validation context, authority, and durable outcome. The Kotlin and Spring backend component must not infer a stronger fact from transport success, cache presence, or an upstream acknowledgement. Its authoritative state is transactional domain state plus replayable processing progress, and every projection must remain rebuildable or reconcilable from committed facts. This framing distinguishes a protocol guarantee from an operational convenience and gives reviewers a concrete place to challenge an assumption. 15
The principal failure to design against is blind retries amplifying a permanent failure or changing user intent. Address it before optimizing by defining a narrow ownership boundary, stable identities, bounded resource use, and a machine-readable outcome for every rejected transition. Record typed errors mapped consistently across logs, metrics, APIs, and queues. A reviewer should be able to trace each accepted result to input bytes, rule or policy version, prior state, and commit identity without relying on prose logs. When the authority cannot be reached or context is incomplete, return an explicit unavailable or pending state; do not convert uncertainty into acceptance.
Concurrency control
Treat concurrency control as part of the executable design of Time-Series Data Management for Blockchain Analytics, not as documentation added after coding. The relevant operating envelope includes historical ingestion, bursty APIs, retries, rolling deployment, backfill, and downstream degradation. For each mode, identify which state is authoritative, which work may be retried, what is bounded, and which observation proves progress. This is especially important across HTTP, authentication, messaging, domain, database, and downstream-node boundaries, where delivery and processing are different events and where local time or arrival order may not reflect authoritative order. 13
A useful review asks how the design behaves under lost update, duplicate event, poison record, pool exhaustion, timeout, schema skew, and inconsistent retry. The unsafe outcome is a check-then-act race accepting two individually plausible operations. Prevent it with explicit preconditions and postconditions, and retain a linearization argument plus stress tests at the chosen contention boundary as release evidence. Use stable codes rather than exception text, keep policy configuration versioned, and attach the accepted policy or rule version to durable results. An service or data-platform operator must be able to stop intake, drain or quarantine work, compare local state with authority, and resume without inventing a second side effect.
Idempotency and replay
The implementation of Time-Series Data Management for Blockchain Analytics should expose how duplicate delivery, process restart, and historical backfill preserve the same result through types and module boundaries. Parse external representations once, preserve the original identity when audit or replay needs it, and pass validated domain values inward. Mutations of transactional domain state plus replayable processing progress belong behind one authoritative transition function or transaction boundary. Network clients, storage adapters, user interfaces, and telemetry exporters must not duplicate consensus or business rules. That separation keeps deterministic logic testable and prevents a library upgrade from silently redefining validity. 14
Assume that at-least-once delivery creating a second side effect will eventually occur in a staging fault test or production incident. The control is not a catch-all retry: classify the outcome, decide whether the identical operation is safe to repeat, bound attempts and elapsed time, and surface terminal work for reconciliation. The minimum evidence is stable operation identities, deduplication state, and deterministic replay fixtures. Keep credentials, bearer tokens, signing requests, customer identifiers, and database change history out of ordinary logs, and prefer hashes, version identifiers, counts, and sanitized reason codes. Any emergency bypass must be narrow, time-limited, approved, and observable.
Persistence and atomicity
Verification for Time-Series Data Management for Blockchain Analytics must demonstrate which facts commit together and how derived views catch up at several layers. Small tests cover deterministic transforms and boundary values; contract tests pin serialized forms; integration tests exercise real adapters; replay tests compare state roots or projections; and fault tests interrupt work at every commit boundary. The dataset must include normal history, malformed input, duplicates, reordering, maximum-size values, and changes of rule or schema version. A passing example is evidence about that environment and dataset, not a universal performance claim. 15
Make a crash exposing a cursor that claims work whose state was not committed a named negative test. The release packet should retain transaction boundaries, durable checkpoints, and reconciliation queries, exact dependency and tool versions, the deterministic command, and its result. For performance work, report warm-up, repetitions, concurrency, percentiles, resource limits, and the point where backpressure begins. For security work, include abuse cases and independent review. A change is ready only when failures leave transactional domain state plus replayable processing progress safe, recovery is rehearsed, and telemetry explains both user-visible outcome and operator action.