Historian
The historian stores tag values over time and answers trend queries. It runs as its own service and writes to a QuestDB store.
The path a value takes
- Scaling and deadband are applied at the edge, so stored values are in engineering units and noise never reaches storage.
- The historian stores only tags with history enabled.
- Writes go through the store-and-forward buffer — an unreachable QuestDB buffers and replays in order rather than losing data.
- A 1-minute rollup materialises aggregates for long-range queries.
- A live tail buffer holds the most recent samples in memory and merges them into live chart queries, closing the sub-second window between ingestion and QuestDB's flush.
Enabling history
Per tag: set Enable history, and optionally a store interval and a deadband.
| Property | Effect |
|---|---|
| Enable history | Stream this tag to the historian |
| Deadband | Suppress changes smaller than this — the biggest lever on volume |
| Store interval (ms) | Force a point at this interval even without change, proving the signal was alive |
One designated store
Exactly one QuestDB connection is the system historian, named by a single system setting rather than a per-connection flag — so "two historians" cannot be represented at all.
Only that connection (plus any still holding historised tags) is provisioned with a historian table, a rollup, WAL settings, an ingestion worker and a retention sweep. A QuestDB connection added purely as a data source is left alone.
History epochs
Changing the historian would ordinarily truncate every chart at the switchover: a "last 30 days" query issued against the new store returns only the days since the change, with no sign the rest exists.
QUBIQ records an epoch instead: connection X was the historian from t1 to t2. A read resolves its window to the overlapping epochs, queries each one's store, and stitches the timeline back together.
Two consequences worth knowing:
- Migrating the historian is non-destructive. Trends span the change.
- Retiring a store means retiring its epoch, not deleting history you still want to read.
Range statistics are recombined exactly across epochs — min/max are extremal, counts and sums additive, and averages and standard deviations are reconstructed from the (Σx², Σx, n) trio rather than being averaged, which would be wrong whenever epochs hold different sample counts.
Store ownership
Two QUBIQ installations writing to one QuestDB historian table is silent corruption. An
application-level check cannot see another machine, so QUBIQ records physical ownership inside the
store itself.
A store owned by a different installation — a cloned VM, a restored backup, a decommissioned instance — is refused, with an ownership banner. Claiming it is a deliberate, audited action.
→ QuestDB
Self-healing
Three mechanisms keep history flowing without operator action:
| Mechanism | Handles |
|---|---|
| Schema-drift detection | QuestDB auto-creating a table with the wrong designated timestamp, which would silence every read. Detected, alarmed, and repairable by rebuild. |
| WAL supervision | Tables suspended by a failed write-ahead-log apply. Recoverable stalls resume automatically; poison segments are alarmed rather than looped on. |
| Rollup rebuild | A stale or incorrect 1-minute aggregate, rebuilt on demand. |
Automatic repair declines above a size threshold, so a configuration change cannot trigger a minutes-long re-aggregation unannounced at boot. The operator-triggered rebuild is the deliberate counterpart.
Querying
| From | How |
|---|---|
| A screen | Historian or HmiTrendChart widget |
| A script | system.hist.getTrends(paths, start, end, maxPoints, agg) |
| A pipeline | The Python node, via system.hist |
Always bound the result. A day of one-second data is 86,400 points per tag; the server aggregates to
your maxPoints target so the browser receives something it can actually draw.
Retention
A sweep runs daily and drops whole partitions past the configured age. Partition drops are metadata operations in QuestDB, so retention is nearly free — which is why day-granular partitioning is the sensible default.
Set deadbands before you set retention. Not storing a row is far cheaper than storing and later deleting it.
What the historian is not
- Not a general data warehouse. It stores tag time-series. Batch records, orders and documents belong in SQL or MongoDB.
- Not the audit journal. Security events go to a separate external database, deliberately outside QUBIQ's control. → Audit journal
- Not a backup. History is not included in a configuration backup; QuestDB is backed up by your normal database procedures.
In this section
| Page | Contents |
|---|---|
| Configuration | Designating the store, tuning ingestion, retention |
| Querying history | Trends, aggregation, statistics and performance |