Skip to main content
Version: 1.0.8

Historian

The historian stores tag values over time and answers trend queries. It runs as its own service (QBQ-Historian) and writes to a QuestDB store.

QuestDB 9.4.0 or later is required

From 1.0.8 the historian depends on QuestDB 9.4 features. Multi-tag charts use them directly. Upgrade QuestDB before you upgrade QUBIQ. A store older than 9.4.0 is refused when you designate it, and the refusal names the version it found. A store that is already the historian keeps ingesting, so an upgrade notice never costs you data. Its charts are not guaranteed to work, though, and every start logs a critical error until QuestDB is upgraded. → Configuration

The path a value takes​

A device reading passes through the protocol worker to the historian, which writes to the historian store, buffers while the store is unreachable, keeps a live tail of recent samples, and serves charts from the store, the rollup or the tail.A device reading passes through the protocol worker to the historian, which writes to the historian store, buffers while the store is unreachable, keeps a live tail of recent samples, and serves charts from the store, the rollup or the tail.
Charts read the rollups for long ranges and the live tail for the last few minutes.
  1. Scaling is applied at the edge, so stored values are in engineering units.
  2. The historian stores only tags with history enabled.
  3. Each reading is stored at its event time: the device's own timestamp when the device sends a plausible one, otherwise the time the server received it. The row also records its quality, and where the time came from. → Quality and time
  4. The tag's storage rules decide which readings become rows: the deadband (absolute or a percent of range), the minimum time between samples, and the store interval. A change of quality is always stored. → Storage rules
  5. Writes go through the store-and-forward buffer. An unreachable QuestDB buffers and replays in order rather than losing data.
  6. Three rollup tiers (1 minute, 1 hour and 1 day) pre-aggregate for long-range trends. → Rollup tiers
  7. A live tail buffer holds the most recent samples in memory and merges them into live chart queries. It covers the sub-second window between ingestion and QuestDB's flush.

Enabling history​

Per tag, on the tag's History tab, or for many tags at once from the tree's Enable History… menu:

PropertyEffect
Enable HistoryRecord this tag's values
DeadbandStore a value only when it moved by at least this much, in units or as % of range. The biggest lever on volume.
Min time between samples (ms) 1.0.8Store at most one value per this interval
Store interval (ms)Store the current value again after this long without a stored row, so a value that holds still keeps a recent sample
Interpolation 1.0.8How the stored values connect on trends: Auto, Linear or Step

→ Storage rules · Tag properties

Quality is stored with the value New in 1.0.8​

Every row carries its quality, Good, Uncertain or Bad, and a non-Good row also keeps the device's reason (Unknown: Connection down). When a device goes Bad, history shows it as Bad. It does not show the last value carried on as if nothing had happened.

  • Bad rows are left out of every value and every aggregate: the line, the averages, the rollups and the statistics. A Bad row holds the last known value, not a measurement.
  • Charts shade the stretches that were not Good and name the reason under the crosshair.
  • An Unknown quality, which is what a lost connection reports, is stored as Bad.

→ Quality and time

Outages are marked, not drawn over New in 1.0.8​

A tag stored on change writes nothing while its value holds still. On a chart, the stored value is therefore carried forward. That is right while the plant is running, and wrong across an outage nobody recorded. The historian marks two kinds of outage with one Bad row per affected tag. Each marker stops the line and shades the gap with its reason:

MarkerWritten whenReason shown
ShutdownThe whole platform was downShutdown: QUBIQ was not running, no data was collected
Collector downA collector service (QBQ-Bridge, QBQ-Expression) died or was restarted while the rest kept runningCollector down: <service> was not running, no data was collected

When only the historian or QuestDB was down, nothing is marked. The collectors kept publishing into the store-and-forward buffer, which replays the real data.

→ Outage markers

Rollup tiers Changed in 1.0.8​

TierRows per tag per yearServesPartitioned by
Raw (historian)Every stored sampleShort windows, raw export, exact statisticsThe connection's Partition By (Day by default)
1 minute (historian_1m)525,600Windows of 12 hours or moreRollup Partition (Hour by default)
1 hour (historian_1h) 1.0.88,760Weeks to yearsMonth
1 day (historian_1d) 1.0.8365Multi-year trendsYear

A trend reads the coarsest tier that answers it exactly: one whose buckets fit whole inside the chart's buckets on the viewer's time zone. A UTC day chart reads the 1-day tier. A Jakarta day starts at 17:00 UTC, so it reads the 1-hour tier instead. A tier that is missing or behind is skipped, and the chart reads the next finer source.

Each tier is built from the raw table and has its own retention. Repairing one never invalidates another, and the coarse tiers can keep years of trend after the raw rows have expired.

One designated store​

Exactly one QuestDB connection is the system historian. A single system setting names it; there is no per-connection flag, so "two historians" cannot be represented at all.

Only that connection, plus any still holding historised tags, gets a historian table, rollups, WAL settings, an ingestion worker and retention. A QuestDB connection added purely as a data source is left alone.

→ Historian configuration

History epochs​

Changing the historian would ordinarily truncate every chart at the switchover. A "last 30 days" query against the new store would return 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 and max are extremal; counts, sums, time-weighted sums, totals, counter increases and times in state are additive. Averages and standard deviations are rebuilt from the (Σx², Σx, n) trio. Averaging them would be wrong whenever the 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, such as a cloned VM, a restored backup or a decommissioned instance, still receives history. But QUBIQ makes no schema changes to it, does no rollup maintenance and applies no retention, and Settings → Historian shows an ownership banner. Claiming the store is a deliberate, audited action.

→ QuestDB

Self-healing, within limits​

MechanismHandles
Schema-drift repairA historian table missing columns, deduplication or its index is repaired in place. One QuestDB auto-created with the wrong designated timestamp cannot be repaired in place and is reported.
WAL supervision Changed in 1.0.8A table QuestDB suspended. Resource problems resume once the resource is freed. Anything else raises a critical alarm. Transactions are never skipped automatically.
Rollup repair Changed in 1.0.8An invalid rollup tier is rebuilt automatically only when the rebuild loses nothing. Otherwise it raises an alarm and waits for you.

Rebuilding a rollup re-aggregates it from the raw table. Once retention has expired raw rows that a tier still holds, a rebuild would delete that older tier history. So the automatic path declines, and the decision is yours. → Repairing a store

Querying​

FromHow
A screenHistorian, HmiTrendChart or HmiSparkline widget
A scriptsystem.hist.getTrends, getStats and valueAt → System API
A spreadsheetThe Historian chart's Export → CSV — every stored sample 1.0.8

Always bound the result. A day of one-second data is 86,400 points per tag. The server aggregates to what the chart can draw, and keeps every spike while it does.

→ Querying history

Retention Changed in 1.0.8​

Retention is the table TTL: QuestDB expires whole raw partitions past the configured age. The rollup tiers keep their history independently, each with its own retention, so a five-year trend can outlive one year of raw data.

Retention no longer drops partitions by hand

Up to 1.0.7 a daily sweep ran DROP PARTITION on the raw table. In QuestDB that invalidates every rollup built on it, and the recovery rebuilt the rollups from whatever raw rows were left. On every install with retention set, the 1-minute rollup's older history was destroyed each day. 1.0.8 sets a TTL instead, and the views stay valid with all their history. Rollup history that was lost before the upgrade does not come back.

Set storage rules before you set retention. Not storing a row is far cheaper than storing it and deleting it later.

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. A configuration backup does not include history. Back up QuestDB with your normal database procedures.

In this section​

PageContents
ConfigurationQuestDB version, designating the store, storage rules, retention, repair, alarms
Quality and timeQuality in history, event time and clock skew, heartbeats, outage markers
Querying historyRetrieval modes, statistics, value at an instant, export, performance
AnnotationsNotes on tag history, who may write them, and where they are kept