Download Latest Version utils-8.3.1.jar (28.1 MB)
Email in envelope

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

Home / 9.0.0
Name Modified Size InfoDownloads / Week
Parent folder
questdb-9.0.0-no-jre-bin.tar.gz 2025-07-11 26.3 MB
questdb-9.0.0-rt-linux-x86-64.tar.gz 2025-07-11 66.3 MB
questdb-9.0.0-rt-windows-x86-64.tar.gz 2025-07-11 62.4 MB
9.0.0 source code.tar.gz 2025-07-11 55.9 MB
9.0.0 source code.zip 2025-07-11 60.6 MB
README.md 2025-07-11 17.6 kB
Totals: 6 Items   271.6 MB 4

Major release - QuestDB 9.0!

We've acted on key feedback from leading firms, and open source users alike, and channelled this into the most featureful and robust version of QuestDB yet!

If you are a long-term user, we hope you will enjoy some of the great additions we're bringing in this release, and if you are a new user, there's never been a better time to get started!

Multidimensional Arrays

This milestone release brings the much-anticipated first beta release for our new Multidimensional Arrays (NDArrays). These are true shaped-and-strided, NumPy-like arrays, perfect for storing tick and order book data, signals from sensor arrays, ML weights, and much more. This initial release supports the DOUBLE[] type, of n-dimensions, and we will expand this to other types soon!

image

Common array operations (e.g. slicing, transposing) are handled with zero copying. Instead, the underlying buffer is shared between different operators, whether the arrays are stored on-disk or in-memory. The data is contiguous, and stored as a true tensor rather than nested lists.

A number of common array operations are included, and we will be rapidly releasing more, so get your feedback in early!

Binary line protocol

Another kicker - this release brings the first part of our new binary line protocol. In order to support writing arrays with maximum performance, we've extended the ILP text protocol with new binary types, including the binary double[] and binary double. This increases throughput and lowers message size, versus sending arrays in a textual format. This has been introduced as a new protocol version, maintaining backwards compatibility with existing clients.

Here's an example that demonstrates sending double[] to QuestDB from a Pandas DataFrame:

:::python
import pandas as pd
from questdb.ingress import Sender

df = pd.DataFrame({
    'symbol': pd.Categorical(['ETH-USD', 'BTC-USD']),
    'side': pd.Categorical(['sell', 'sell']),
    'price': [2615.54, 39269.98],
    'amount': [0.00044, 0.001],
    'ord_book_bids': [
        np.array([2615.54, 2618.63]),
        np.array([39269.98, 39270.00])
    ],
    'timestamp': pd.to_datetime(['2021-01-01', '2021-01-02'])})

conf = f'http::addr=localhost:9000;'
with Sender.from_conf(conf) as sender:
    sender.dataframe(df, table_name='trades', at='timestamp')

This is a key turning point for QuestDB's ingestion clients. Introducing this new binary protocol opens the door for us to make clients smarter, and enable native integration with key QuestDB features such as data deduplication, schema evolution, and replication failover.

Materialized Views

Materialized Views have received major upgrades - efficient writes with the new replace commit mechanism, support for self-UNION queries, the ability to delay or defer a refresh, and three new view refresh modes:

  • TIMER refreshes (now stabilised), allowing you to refresh the view after a regular time interval.
  • MANUAL refreshes, which are entirely user-controlled.
  • PERIOD refreshes, with more explanation below!

PERIOD refresh is the most featureful mode to date, bringing time-zone aware, calendar-scheduled refreshes, only including complete buckets of data. This has great potential, especially for users with globally-distributed use cases.

For example, let's say you want to summarise trading data at the end of each trading day, but you work with exchanges in different timezones. You can create a PERIOD view for NYSE data tuned to update at the end of the New York trading day. Then you can have a separate view specifically for Tosho data, wich updates at the end of the Tokyo trading day - and all with easy-to-use syntax.

:::sql
CREATE MATERIALIZED VIEW trades_latest_1d
REFRESH PERIOD (LENGTH 1d TIME ZONE 'America/New_York' DELAY 2h) AS
SELECT 
    timestamp, 
    symbol, 
    side, 
    last(price) AS price, 
    last(amount) AS amount, 
    last(timestamp) AS latest
FROM trades
SAMPLE BY 1d;

We won't stop to iterating on killer features like Materialized Views, and Multidimensional Arrays!

Web Console

Our web console has had a fresh coat of paint, and with it comes some long sought-after features.

Firstly, each query is now marked by its own individual run arrow and selection, making it easy to see at a glance where your semi-colon delineated boundaries lie. Also, you can now easily obtain query plans by right clicking on the run arrows, to help you better understand and debug troublesome queries - no more typing out the EXPLAIN keyword, only to delete it straight afterwards!

image

Additionally, the QuestDB web console now supports running multiple queries at once, through drag selection and the Run All button.

The results from Run All are stored in a new Query Log, which is particularly handy when running database migration scripts, and you can configure the run to stop automatically if any of the queries fail.

image

We've refreshed our Web Console documentation, and invite you to take a tour of our new features.

Roundup

This is a big one, but we're just getting started! We're grateful to our customers and users, and thank you for your ongoing support and constructive feedback - we can't do it without you.

We'll end it here so you can get busy upgrading to QuestDB 9.0.0, but don't forget to check out all the other performance upgrades, new functions, and (of course) bug fixes that come with this milestone release.

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

See also our prettier release notes page.

Breaking changes 💥

  • Materialized Views
    • REFRESH LIMIT and REFRESH EVERY settings have been reset, due to a change in storage format.
      • REFRESH EVERY (TIMER views) must be dropped and recreated.
      • REFRESH LIMIT can be re-added with an alter
        • ALTER MATERIALIZED VIEW trades_latest_1d SET REFRESH LIMIT 1 WEEK;
    • TIMER refresh syntax has been inverted from what is was originally:
      • Instead of REFRESH START <timestamp> EVERY <interval>
      • It is now REFRESH EVERY <interval> START <timestamp>
    • REFRESH INCREMENTAL has been changed to REFRESH IMMEDIATE (but older syntax is still accepted).
  • Column Aliasing
    • The aliasing rules for expressions without explicit aliases have now been changed.
    • Previously:
      • SELECT spread(bid, ask) would give an output column of spread.
      • Repeated functions would have a number appended
      • Plain expressions such as 5 + 2 would be named column.
    • Going forward:
      • The expression itself will be used as the column name:
        • floor(avg(price*amount)) now outputs floor(avg(price * amount)) as the column name.
        • Repeated expressions (which are unlikely), will have numbers appended.
        • The max length of the output column alias is configurable: cairo.sql.column.alias.generated.max.size
        • This change can be reverted (for now) using cairo.sql.column.alias.expression.enabled=false.
  • PG Wire
    • Users who opted out of the new faster and less buggy PG Wire implementation have been opted back in.
    • The new PG Wire driver was initially released in September 2024, and we consider it robust and stable.
    • If users need to opt back out, they can do so by changing pg.legacy.mode=!true, but should adopt the new modern PG Wire server as soon as possible, as we will remove this option soon.
  • JOIN
    • TOLERANCE is now a keyword, so if you were using it in implicit aliasing, it will need to be quoted i.e. "TOLERANCE".

Highlights

  • Multidimensional arrays
    • New double[] type, which is a shaped-and-strided n-dimensional array.
    • Addition of new binary protocol to ILP clients to efficiently send double and double[] types.
      • Literals: SELECT ARRAY[1.0, 2.0, 3.0]
      • 2D: SELECT ARRAY[[a], [b]] FROM tango
      • Indexing: SELECT arr[1][2] FROM samba or SELECT arr[1,2] FROM samba
      • Slicing: SELECT arr[2:], arr[1:100] FROM samba
      • ND Slicing: SELECT arr[2:3, 3:4], arr[1:, 2] FROM samba
      • Math: SELECT a * b FROM samba
      • Functions: SELECT matmum(arr, transpose(arr)) FROM samba
  • Materialized Views
    • View updates are much faster due to new timestamp range-replace commits.
    • TIMER views have been stabilised, and now offer a new TIME ZONE clause, to make your refresh timezone-aware.
    • MANUAL refresh mode has been added, for fully manual (but incremental) view refreshing.
    • CREATE MATERIALIZED VIEW now accepts a DEFERRED clause, to delay or prevent the initial eager refresh upon view creation.
    • REFRESH LIMIT is now respected during a full view refresh.
    • PERIOD refresh mode has been added, which supports calendar-scheduled, timezone-aware refreshes, for only whole sample by buckets.
    • Self-UNION queries are now supported. possibly be found.
  • SQL
    • JOIN
      • CROSS JOIN queries have been sped up significantly, after identifying an issue with cursor resets.
      • ASOF and LT joins now support a TOLERANCE clause, which specifies a maximum bound for the timestamp matching
        • SELECT ... FROM table1 ASOF JOIN table2 ON <key> TOLERANCE interval_literal [WHERE ...]
      • Time-based joins on SYMBOL columns have been sped up through early-exits when it is known that no SYMBOL match can
    • SELECT
      • Columns within in a SELECT statement are now self-referenceable and memoised.
        • This is convenient and also improves the efficiency of functions such as json_extract.
        • For example, SELECT x + 10 y, y - 5 FROM test.
    • A new generate_series() function has been added.
      • This is a pseudo-table allowing for timestamp, double and long range generation.
      • SELECT * FROM generate_series('2025-06-13T09:00:00', '2025-06-13T10:00:00', '1m');
      • Negative steps can be used, to produce values in descending order.
  • DEDUP
    • Data deduplication performance has been dramatically improved when inserting completely identical data en-masse.

Changelist

New Contributors

Full Changelog: https://github.com/questdb/questdb/compare/8.3.3...9.0.0

Source: README.md, updated 2025-07-11