Skip to main content
Version: 1.0.5

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:

Press Take ownership of this store in Settings → Historian (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 and logs it as an error in System Logs; it is not alarmed. Missing columns, deduplication keys and the index are repaired in place automatically. The rest:

RepairWhen
Rebuild rollup (historian_1m)The 1-minute aggregate is stale or wrong. Press it in Settings → Historian (needs Edit connections).
Table rebuildThe base table has the wrong designated timestamp. QuestDB cannot rename one, so the data must be copied into a correctly-shaped table. There is no button for it; the historian logs that a rebuild is required — contact support.

A rollup rebuild 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.

The Data Retention (days) field is not saved

The QuestDB form shows a Data Retention (days) field, but this release never saves it: the value is not sent when the connection is saved and is not read back. Setting it in the form has no effect.

→ 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 — the table must be rebuilt; contact support.
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