Zero‑Copy Analytics: Querying Remote Parquet Files Directly with DuckDB
Discover how DuckDB lets you query remote Parquet files directly, reducing data egress and speeding up analytics with zero‑copy, predicate pushdown, and an in‑process columnar engine.
16 Nov 2025, 01:16 UTC

Why the Load‑Then‑Query Pattern Is a Bottleneck
Data engineers routinely pull Parquet files from cloud storage, load them into a local database or a pandas DataFrame, and then run analytics. The copy step inflates network egress, increases storage costs, and introduces latency that can dwarf the actual query time. For exploratory analysis or ad‑hoc reporting, this overhead is unnecessary.
DuckDB’s In‑Process Columnar Engine
DuckDB is a single‑process, columnar OLAP engine that runs inside the same runtime as your application. It can read Parquet files directly, apply predicate pushdown, and return results without materializing the entire dataset. The key feature that enables remote querying is the http_fs extension, which speaks HTTP/REST to object stores like S3, GCS, and Azure Blob.
How Predicate Pushdown Saves Bandwidth
Parquet stores metadata for each row group: the minimum and maximum values of every column. When DuckDB sees a WHERE clause, it first downloads only the metadata, determines which row groups can contain matching rows, and then issues HTTP range requests for just those byte ranges. In practice, a 10 GB dataset can be filtered down to a few megabytes of data.
Concrete Example: Querying S3 from Python
Below is a minimal, reproducible snippet. Replace the placeholder credentials with your own or use environment variables.
import duckdb
# Connect and load the HTTP file system extension
con = duckdb.connect()
con.execute("LOAD http_fs;")
# Configure S3 credentials – for production, use environment vars
con.execute("SET s3_access_key_id = 'YOUR_KEY';")
con.execute("SET s3_secret_access_key = 'YOUR_SECRET';")
con.execute("SET s3_region = 'us-east-1';")
# Query a remote Parquet dataset with a filter
query = """
SELECT
region,
AVG(sales) AS avg_sales,
COUNT(*) AS transaction_count
FROM 's3://my-bucket/data/2023/*.parquet'
WHERE date > '2023-01-01'
GROUP BY region
ORDER BY avg_sales DESC;
"""
# Execute and collect the result as a pandas DataFrame
result = con.execute(query).df()
print(result)
DuckDB internally performs HTTP range requests. The EXPLAIN command can confirm that the query plan includes FILTER and PROJECTION steps before any data is transferred.
Verification Checklist
- Predicate Pushdown: Run
EXPLAIN SELECT * FROM 's3://bucket/file.parquet' WHERE column = 42;and look for aFILTERnode that references the column. - Memory Limits: In a shared environment, set
SET memory_limit = '2GB';to avoid exhausting system RAM during large joins. - Remote vs. Local Performance: Time a simple
SELECT COUNT(*) FROM 's3://bucket/file.parquet';against the same file stored locally. The difference highlights network impact.
Trade‑offs and Limitations
- Concurrency: DuckDB is single‑threaded per connection. It is not a replacement for a multi‑tenant data warehouse when you need hundreds of concurrent users.
- Full Table Scans: If your query lacks a
WHEREclause, DuckDB must download the entire file, making it no better than a local read. - Out‑of‑Core Workloads: For datasets larger than RAM, DuckDB spills to disk. Monitor swap usage to ensure the process does not thrash.
- Security: Credentials are stored in connection settings. Use IAM roles or environment variables to avoid hard‑coding secrets.
Actionable Takeaways
- Use DuckDB for rapid, exploratory analytics against cloud‑stored Parquet without an ETL step.
- Enable
http_fsand configurememory_limitearly to control resource usage. - Run
EXPLAINbefore production queries to verify that predicate pushdown is active. - When scaling to many concurrent users, consider a dedicated warehouse; DuckDB excels at single‑user, high‑throughput reads.
Conclusion
DuckDB turns cloud object storage into an instant data lake database. By eliminating the copy‑step and leveraging columnar storage and predicate pushdown, you can dramatically reduce egress costs and accelerate interactive analysis. The trade‑offs are clear: it is not a high‑concurrency transactional engine, but for the common use‑case of ad‑hoc analytics it offers a lightweight, zero‑copy solution.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.