| Name | Modified | Size | Downloads / 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 (
DECIMAL8throughDECIMAL256) 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
- fix(core): suppress error output in print-hello.sh during startup failure by @ideoma in https://github.com/questdb/questdb/pull/6738
- feat(core): support reading secrets from files for Kubernetes deployments by @bluestreak01 in https://github.com/questdb/questdb/pull/6719
- feat(core): optimize parquet partition read with late materialization, zero-copy page reading, and use raw array encoding by @kafka1991 in https://github.com/questdb/questdb/pull/6675
- fix(http): prevent parquet export corruption under concurrent connections by @jerrinot in https://github.com/questdb/questdb/pull/6723
- perf(parquet): speed up parquet writing by @ideoma in https://github.com/questdb/questdb/pull/6735
- feat(sql): allow underscore number separator in TICK syntax by @mtopolnik in https://github.com/questdb/questdb/pull/6749
- fix(core): correct greedy parsing for single N pattern in timestamp formats by @jerrinot in https://github.com/questdb/questdb/pull/6741
- fix(core): fix intermittent backup failures on Windows caused by file access problems by @RaphDal in https://github.com/questdb/questdb/pull/6748
- fix(core): clear changedKeys at start of config reload to prevent stale notifications by @bluestreak01 in https://github.com/questdb/questdb/pull/6756
- fix(sql): fix ADD COLUMN IF NOT EXISTS for DECIMAL, GEOHASH, and array types by @mtopolnik in https://github.com/questdb/questdb/pull/6753
- feat(core): add JIT support for aarch64 by @RaphDal in https://github.com/questdb/questdb/pull/6758
- feat(sql): window definition by @javier in https://github.com/questdb/questdb/pull/6746
- fix(sql): reject trailing content after valid query by @mtopolnik in https://github.com/questdb/questdb/pull/6751
- fix(core): fix assertion errors in UNION ALL with column count mismatch by @mtopolnik in https://github.com/questdb/questdb/pull/6744
- fix(core): add dedicated batch size config for parquet export by @ideoma in https://github.com/questdb/questdb/pull/6747
- fix(sql): fix table and name-lock leak on CREATE TABLE AS SELECT failure by @kafka1991 in https://github.com/questdb/questdb/pull/6763
- fix(ilp): fix assertion error in ILP decimal parser on malformed input by @bluestreak01 in https://github.com/questdb/questdb/pull/6772
- perf(sql): improve performance of UNION and friends by pushing down timestamp filter into subqueries by @mtopolnik in https://github.com/questdb/questdb/pull/6745
- fix(sql): fix to recognise view names in quotes by @glasstiger in https://github.com/questdb/questdb/pull/6771
- fix(sql): fix alias hiding original column name in CASE with window function by @mtopolnik in https://github.com/questdb/questdb/pull/6775
- fix(sql): compile tick expressions with date variables into IR for zero-parse evaluation when executing caches SQL statements by @bluestreak01 in https://github.com/questdb/questdb/pull/6780
- fix(core): fix checkpoint timeout caused by slow sync() system call by @glasstiger in https://github.com/questdb/questdb/pull/6785
- perf(sql): speed up parallel GROUP BY and Top K queries by @mtopolnik in https://github.com/questdb/questdb/pull/6754
- feat(sql): add twap() time-weighted average price aggregate function by @bluestreak01 in https://github.com/questdb/questdb/pull/6786
- feat(parquet): add decimal type support for parquet read/write by @RaphDal in https://github.com/questdb/questdb/pull/6725
- perf(sql): optimize CASE WHEN on symbol columns to compare by int key instead of string by @bluestreak01 in https://github.com/questdb/questdb/pull/6788
- fix(sql): ensure
FILL(LINEAR)respects theFROMclause by @nwoolmer in https://github.com/questdb/questdb/pull/6790 - fix(sql): fix stale interval evaluation for tick expressions with date variables in filter functions by @bluestreak01 in https://github.com/questdb/questdb/pull/6798
- perf(sql): improve double-to-decimal cast performance by @mtopolnik in https://github.com/questdb/questdb/pull/6792
- perf(sql): optimize ORDER BY on computed expressions with sort key materialization by @bluestreak01 in https://github.com/questdb/questdb/pull/6793
- feat(sql): Add array_build() function for dynamic array construction by @javier in https://github.com/questdb/questdb/pull/6794
- perf(sql): improve double-to-decimal conversion with bulk multiply by @mtopolnik in https://github.com/questdb/questdb/pull/6799
- feat(sql): horizon join for markout analysis by @puzpuzpuz in https://github.com/questdb/questdb/pull/6635
- fix(http): fix server crash on chunked transfer encoding with overflowing chunk size by @bluestreak01 in https://github.com/questdb/questdb/pull/6802
- fix(sql): NullPointerException when right-hand query in window join has timestamp filter by @puzpuzpuz in https://github.com/questdb/questdb/pull/6806
- perf(sql): avoid temp table materialization for Parquet export with computed columns by @mtopolnik in https://github.com/questdb/questdb/pull/6795
Full Changelog: https://github.com/questdb/questdb/compare/9.3.2...9.3.3