Skip to main content
Version: 1.0.4

QuestDB

QuestDB is QUBIQ's time-series store. A QuestDB connection can serve two purposes:

  1. The system historian — the one connection designated to receive tag history.
  2. A data source — queried like any SQL connection, without being the historian.

Only one connection may be the historian at a time.

Configuration

FieldDescription
NameConnection identifier.
HostQuestDB host.
PortPostgres-wire query port, 8812 by default.
ILP portLine-protocol ingestion port, 9009 by default.
Database / Username / PasswordQuery credentials.
Use TLSEncrypt the connections.
ILP authEnable token authentication for ingestion.
ILP token / key IDILP credentials, when ILP auth is enabled.
AI username / passwordOptional read-only credential for the AI assistant.

Two ports, two protocols: ILP for writes (fast, append-only, fire-and-flush) and pgwire for reads (SQL). Both must be reachable.

Historian tuning

These apply when the connection is the designated historian.

FieldMeaningGuidance
Worker countParallel ILP senders1–4. More only helps at high tag counts.
Auto-flush rowsFlush after N buffered rowsHigher = better throughput, higher latency to visibility.
Auto-flush intervalFlush after N milliseconds regardless of row countBounds visibility latency on slow-moving plants.
DeduplicationEnable QuestDB DEDUP UPSERT KEYSMakes replayed writes idempotent. Leave on.
PartitionBase table partition unit (DAY, HOUR, MONTH)DAY suits most plants; retention drops whole partitions.
Rollup partitionPartition unit for the 1-minute rollupCoarser than the base table.
Rollup refresh everyHow often the rollup re-aggregatesBalance freshness against load.
Flush lag is hidden from charts

Between ingestion and QuestDB's flush there is a sub-second window where a value is stored but not yet queryable. The historian keeps a small in-memory tail of recent samples and merges it into live chart queries, so charts look live despite batched writes.

Deduplication matters

Store-and-forward can replay a batch that was written but not acknowledged — a crash between flush and ack. With DEDUP UPSERT KEYS on, the replay overwrites identical rows instead of duplicating them. Turning dedup off trades correctness for a small write gain; do not.

Designating the historian

Exactly one QuestDB connection stores tag history, named by a system setting rather than a per-connection flag — so a two-historian state cannot be represented at all.

The designation lives in Settings → Historian. Reading it needs View connections; changing it needs Edit connections.

Only the designated 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 stays untouched.

Historian configuration

Ownership

Two QUBIQ installations writing to one QuestDB historian table is silent corruption: interleaved tag IDs, doubled counts, unexplainable gaps. QUBIQ therefore records physical ownership inside the store itself, not in its own database — an application-level "only one historian" check cannot see another machine.

If a store is owned by a different installation (a cloned VM, a restored backup, a decommissioned instance), QUBIQ refuses to write and shows an ownership banner. Claiming it is deliberate and audited:

Use Take ownership on the connection (needs Edit connections). Confirm the previous owner is truly retired before doing this.

Schema drift and repair

QuestDB auto-creates a table for an ILP line that arrives for a table that does not exist — with a schema QUBIQ did not choose: the designated timestamp named timestamp instead of ts, no dedup keys, no index. Every read path expects ts, so the historian goes silent with "Invalid column: ts".

QUBIQ detects this, alarms on it, and offers two repairs:

RepairWhen
Rebuild rollupThe 1-minute aggregate is stale or wrong.
Rebuild tableThe base table has the wrong designated timestamp. QuestDB cannot rename one, so the data is copied into a correctly-shaped table.

Both require Edit connections. Both can take minutes on a large store — which is exactly why the automatic path declines above a size threshold and leaves the decision to an operator.

Write-ahead-log supervision

QuestDB applies writes through a WAL. If the apply job hits an unrecoverable error the table is suspended: rows keep landing in the WAL, nothing is applied, and charts go silent.

The historian watches for this and distinguishes two cases:

  • Recoverable stall — resumed automatically.
  • Poison or missing segment (after a disk event or unclean restart) — alarmed for operator attention, because blindly resuming would loop.

Retention

The retention 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.

Historian configuration

Using QuestDB as a plain data source

A QuestDB connection that is not the historian behaves like any SQL connection: named queries, query bindings, pipeline SQL nodes, system.db.runQuery. Useful for time-series you ingest by other means.

The QuestDB pipeline node has two modes: ingress (high-speed ILP writes) and SQL query. → Pipeline nodes

Sizing

FactorEffect
Tag count with history enabledLinear on write rate
Change rate and deadbandThe biggest lever — a 1%-of-span deadband often removes 90% of rows
Retention windowLinear on disk
Partition sizeAffects drop granularity, not total size

Estimate ≈ tags × writes-per-second × 86,400 × retention-days rows, then apply QuestDB's compression. Set deadbands before you set retention; it is far cheaper to not store a row.

Troubleshooting

SymptomCheck
Reads work, writes do notILP port blocked, or ILP auth enabled without a valid token.
"Invalid column: ts"Schema drift — rebuild the table.
Charts stop but ingestion looks fineTable suspended by a failed WAL apply.
Ownership bannerAnother installation claims this store.
Data appears seconds lateAuto-flush interval too high; lower it or accept the live-tail merge.
Disk filling faster than expectedDeadbands not configured, or history enabled on chattering tags.

Next

Media servers · Historian