Download Latest Version questdb-9.3.4-rt-linux-x86-64.tar.gz (84.6 MB)
Email in envelope

Get an email when there's a new version of QuestDB

Home / 9.3.3
Name Modified Size InfoDownloads / Week
Parent folder
questdb-9.3.3-no-jre-bin.tar.gz 2026-02-25 34.2 MB
questdb-9.3.3-rt-linux-x86-64.tar.gz 2026-02-25 91.2 MB
questdb-9.3.3-rt-windows-x86-64.tar.gz 2026-02-25 81.6 MB
9.3.3 source code.tar.gz 2026-02-25 62.9 MB
9.3.3 source code.zip 2026-02-25 68.3 MB
README.md 2026-02-25 11.7 kB
Totals: 6 Items   338.2 MB 0

QuestDB 9.3.3

QuestDB 9.3.3 is a feature-rich release introducing HORIZON JOIN for markout analysis, a new twap() aggregate, SQL-standard WINDOW definitions, JIT compilation on ARM64, and file-based secrets for Kubernetes deployments. It also brings significant performance improvements across Parquet I/O, parallel GROUP BY, UNION queries, and ORDER BY on computed expressions.

For any questions or feedback, please join us on Slack or on Discourse.

See also our prettier release notes page.

Highlights

HORIZON JOIN for markout analysis

HORIZON JOIN is a new join type designed for markout analysis — a common financial analytics pattern where you measure how prices or metrics evolve at specific time offsets relative to events like trades or orders.

For each row in the left-hand table and each offset in the horizon, the join computes left_timestamp + offset and performs an ASOF match against the right-hand table. Results are implicitly grouped by the horizon offset and any specified keys, with aggregate functions applied across all matched rows.

Here's an example measuring post-trade price impact at 1-second intervals up to 60 seconds:

:::sql
SELECT h.offset / 1_000_000 AS horizon_sec, t.sym, avg(m.mid) AS avg_mid
FROM trades AS t
HORIZON JOIN mid_prices AS m ON (t.sym = m.sym)
RANGE FROM 1s TO 60s STEP 1s AS h
ORDER BY t.sym, horizon_sec

You can also use LIST for non-uniform horizons and negative offsets to look at pre-event behavior:

:::sql
SELECT h.offset / 1_000_000 AS horizon_sec, t.sym,
       avg(m.mid - t.price) AS avg_markout
FROM trades AS t
HORIZON JOIN mid_prices AS m ON (t.sym = m.sym)
LIST (-5s, -1s, 0, 1s, 5s, 30s, 1m) AS h
ORDER BY t.sym, horizon_sec

The horizon pseudo-table exposes h.offset (raw microsecond value) and h.timestamp (the computed left_timestamp + offset), which can be used in expressions and grouping.

twap() time-weighted average price

The new twap(price, timestamp) aggregate computes the time-weighted average price using step-function integration: each price is held constant until the next observation, and the TWAP is the area under the step function divided by the total time span. It supports parallel GROUP BY and SAMPLE BY with FILL modes.

:::sql
SELECT symbol, twap(price, timestamp) AS twap_price
FROM trades
WHERE timestamp IN today()
SAMPLE BY 1h;

WINDOW definition clause

QuestDB now supports the SQL-standard WINDOW clause for defining reusable window specifications. Instead of repeating the same PARTITION BY and ORDER BY in multiple window function calls, define them once and reference by name:

:::sql
SELECT symbol, side, price,
       sum(price) OVER ws, avg(price) OVER ws,
       sum(amount) OVER ws, sum(price) OVER wt
FROM trades
WINDOW wt AS (ORDER BY timestamp),
       ws AS (PARTITION BY symbol, side ORDER BY timestamp);

Window inheritance is also supported, where a named window references another as its base:

:::sql
SELECT avg(price) OVER w2
FROM trades
WINDOW w1 AS (PARTITION BY symbol ORDER BY ts),
       w2 AS (w1 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)

Chained inheritance and standard merge rules for PARTITION BY, ORDER BY, and frame clauses are all supported.

JIT compilation on ARM64

QuestDB's JIT filter compiler now runs natively on ARM64 (aarch64) systems, including Apple Silicon and AWS Graviton. Previously, JIT-compiled filters were only available on x86. Benchmarks on an Apple M5 show filter evaluations running up to 2x faster with JIT enabled for common WHERE clause patterns, with OR-predicate filters seeing up to 5x improvement.

File-based secrets for Kubernetes

Sensitive configuration like database passwords can now be loaded from files using the _FILE suffix convention, enabling integration with Kubernetes Secrets, Docker Secrets, and HashiCorp Vault:

:::bash
export QDB_PG_PASSWORD_FILE=/run/secrets/pg_password

File-based secrets are automatically trimmed, visible in SHOW PARAMETERS with value_source = 'file', and reloaded when contents change via SELECT reload_config().

array_build() function

The new array_build(nDims, size, filler1, ...) function creates DOUBLE[] or DOUBLE[][] arrays with controlled shape and fill values. The size parameter accepts a scalar integer or a DOUBLE[] (using its cardinality), and each filler can be a scalar (repeated) or an array (copied element-by-element with NaN padding or truncation).

Performance

Parquet I/O

  • Parquet partition reads with selective filters now use late materialization — filter columns are decoded first, and remaining columns are decoded only for matching rows. This gives up to a 2.4x speedup on OHLC-style aggregation queries with symbol filters.
  • Parquet writing has been sped up.
  • Parquet export of queries with computed expressions (e.g., CAST, arithmetic, string functions) no longer falls back to a temporary table. A new hybrid export mode passes raw columns zero-copy and materializes only computed columns into native buffers.
  • Decimal type support (DECIMAL8 through DECIMAL256) has been added for Parquet read and write.

Query execution

  • Parallel GROUP BY and Top K queries now use unordered page frame collection, eliminating head-of-line blocking. At concurrency 8, per-iteration thread spread drops by 53–75%, tail latency (p99) drops by 30–44%, and latency predictability (p99/p50 ratio) improves from 2.5–3.6x down to 1.4–1.8x. There is a 34% single-thread regression for keyed GROUP BY that does not appear under concurrent load.
  • UNION, UNION ALL, EXCEPT, and INTERSECT queries now push designated-timestamp filters into each branch, enabling per-branch partition pruning.
  • CASE WHEN expressions on symbol columns now resolve string constants to integer symbol keys at init time and compare by int at runtime.
  • ORDER BY on computed expressions now pre-computes sort key values into off-heap buffers, reducing function evaluations from O(N log N) to O(N).
  • Double-to-decimal conversion performance has been improved with bulk multiply optimization.

Security

  • Fixed a server crash caused by a crafted HTTP request with an overflowing chunk size in chunked transfer encoding. The hex chunk-size parser now rejects values that would overflow a 64-bit integer.

Changelist

Full Changelog: https://github.com/questdb/questdb/compare/9.3.2...9.3.3

Source: README.md, updated 2026-02-25