Spiral Logo

Latest posts

Faster DuckDB Queries with Vortex

Oct 21, 2026 · by Connor Tsui · 4 min read

This is part one of a series about Vortex and DuckDB. We're starting with a short introduction, and later posts will go into more technical detail.

DuckDB 2.0 has just been released! It brings a new storage format, asynchronous I/O, and improvements to query execution.
If you use Vortex with DuckDB, you might be able to get even faster query performance!
DuckDB supports querying external files (like CSV or Parquet), so we can keep our data in a different format without first loading it into DuckDB's native storage. Vortex is one such file format. Similar to Parquet, it is an open columnar file format built for analytical workloads, but Vortex can also work on data while it is still compressed, which mitigates some of the significant performance costs of decompression.
Vortex is available as a DuckDB core extension on Linux and macOS, so you can read from and write to Vortex files directly inside DuckDB.

How Vortex makes DuckDB faster

Compression can reduce how much data a query reads from disk or object storage, but decompression still takes valuable CPU time. If we can perform an operation before decompressing the data, we can avoid much of that work.
Vortex ships with a highly optimized reader alongside its file format, with code for reading and computing over compressed data. An engine can delegate and "push down" supported operations to this reader, so Vortex can serve DuckDB as well as other database query engines.
DuckDB is responsible for plannig the SQL queries and handles joins and aggregates, while the Vortex reader scans the requested columns and evaluates supported filters. Vortex and DuckDB both work with batches of columnar values, and Vortex can often zero-copy pass the data up to DuckDB.
For example, ClickBench runs 43 analytical queries over hits, a single table of web analytics data. Query 20 counts rows whose URL contains google:
Code Icon
SQL
SELECT COUNT(*)
FROM hits
WHERE "URL" LIKE '%google%';
Vortex can search strings while they're still compressed, and DuckDB counts the matching rows, so we can avoid the work of reconstructing full URLs that the query never returns.
In our ClickBench results, DuckDB + Vortex runs Q20 about 3x faster than both DuckDB + Parquet and DuckDB's native storage. Across all 43 queries, DuckDB + Vortex is about 2x faster than both by geometric mean.
Relative ClickBench query time log scale, lower is faster
Relative to
Q0
Q1
Q2
Q3
Q4
Q5
Q6
Q7
Q8
Q9
Q10
Q11
Q12
Q13
Q14
Q15
Q16
Q17
Q18
Q19
Q20
Q21
Q22
Q23
Q24
Q25
Q26
Q27
Q28
Q29
Q30
Q31
Q32
Q33
Q34
Q35
Q36
Q37
Q38
Q39
Q40
Q41
Q42
Show all timingsHide timings
QueryVortex (ms)Parquet (ms)Native (ms)
Q02.512.916.0
Q17.819.234.8
Q28.427.128.0
Q316.226.626.8
Q457.866.483.7
Q566.091.587.8
Q62.825.330.3
Q79.120.923.1
Q869.179.098.2
Q991.0106.2103.5
Q1027.745.663.2
Q1130.251.967.0
Q1271.899.593.3
Q13129.6163.3167.0
Q1477.4109.999.2
Q1576.893.994.7
Q16143.2181.1192.2
Q17148.2182.7175.3
Q18262.6310.4323.3
Q199.323.823.2
Q2065.6198.4210.5
Q2198.3256.2190.3
Q22178.0331.6201.3
Q2336.8188.084.3
Q2414.636.041.2
Q2519.349.054.6
Q2611.537.241.8
Q2755.9204.2173.1
Q28455.6851.2735.1
Q2918.832.034.8
Q3062.1111.9114.8
Q31112.4168.9169.7
Q32381.7405.1496.2
Q33362.1482.6498.6
Q34365.5486.7506.9
Q3559.465.485.6
Q3612.537.539.4
Q378.828.123.4
Q389.531.027.6
Q3921.063.963.5
Q407.718.822.4
Q418.418.521.8
Q427.518.821.9
ClickBench on local NVMe, from the bench.vortex.dev run for Vortex commit 2e41681 (October 21, 2026). The geomean baseline is the geometric mean of the three times for each query. Hover or tap a row for exact numbers.
Every ClickBench query finishes in under a second with all three formats, so these differences might not matter much on their own. But we also run benchmarks at larger scales, where DuckDB with Vortex is faster than DuckDB with Parquet on local NVMe.

Reading and writing Vortex from DuckDB

Suppose we already have our data in a Parquet file like hits.parquet. After loading the Vortex extension, we can use DuckDB to read that Parquet file and write hits.vortex, then run the same query against the new file:
Code Icon
SQL
INSTALL vortex;
LOAD vortex;

COPY (SELECT * FROM 'hits.parquet')
TO 'hits.vortex' (FORMAT vortex);

SELECT COUNT(*)
FROM 'hits.vortex'
WHERE "URL" LIKE '%google%';
On local storage, you should expect most analytical queries to run faster with Vortex than with Parquet.1 If you want to compare the formats, simply run the same SELECT against hits.parquet (the only difference is the file name in the FROM clause)!
The DuckDB integration guide covers other ways to read and write Vortex files, including files in object storage.

Why store the data in Vortex?

Faster queries are one reason to store data in Vortex. Another reason is that your data can be accessible outside of DuckDB. By keeping it in .vortex files instead of DuckDB's native storage, we can use another engine with Vortex support without having to export the dataset. Parquet is the usual choice for this kind of data, but as the ClickBench results above show, DuckDB can query Vortex faster than Parquet, so we don't have to trade speed for portability.
For example, we can explore hits.vortex in DuckDB but use DataFusion to query the same file from a service, so we don't need a separate copy of the data for each engine or a pipeline to keep those copies in sync. Vortex also works with Apache Arrow, the in-memory columnar format that many data systems share, so the same files work in PyArrow workflows as well as SQL queries.
Sharing files between engines works well for a single dataset, but many teams have to manage large datasets as tables in an open table format such as Apache Iceberg. Iceberg tables keeps track of many data files, along with the table's schema and history. In practice, those data files are almost always Parquet, which means Iceberg tables inherit Parquet's limits: Parquet can be slower to query, and it is hard to extend with new types or encodings.
We want Iceberg users to have a faster, more extensible option, so we've been working on using Vortex files as the data files in Iceberg tables. That technical work is complete, and we're now seeking acceptance from the Iceberg community.
Put together, Vortex can give DuckDB faster queries on data that other engines can still read. If you already use DuckDB, trying Vortex only takes INSTALL vortex;, LOAD vortex;, and a COPY to write your data as a .vortex file. Later posts in this series will go into more technical detail about how DuckDB and Vortex work together.

Footnotes

  1. If they don't, we'd like to hear about it. Join the Vortex Slack or open an issue and tell us about your workload. ↩