C.W.K.
Stream
Lesson 05 of 06 · published

DuckDB — SQL on Files, Without a Database Server

~12 min · duckdb, sql, olap

Level 0Curious Reader
0 XP0/47 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

SQLite for analytics

DuckDB is an in-process OLAP SQL database. The pitch is simple: you pip install duckdb, you write SQL, and you can query Parquet files, Arrow tables, Pandas DataFrames, Polars DataFrames, CSVs — directly, without copying them or loading them into a server. Current stable: 1.5.2.

If SQLite is the in-process database for transactional row-oriented workloads, DuckDB is the in-process database for analytical column-oriented workloads. Same idea — no server, runs in your Python process — different optimization target.

What it's good at

  • Querying Parquet files with column pruning and predicate pushdown automatically.
  • Joining several Parquet files together as if they were tables.
  • Querying a Pandas/Polars DataFrame with SQL when SQL is the more natural way to express the transformation.
  • Acting as an analytical "warehouse" for medium-sized data (hundreds of GB) where spinning up Snowflake would be overkill.

What it's not

DuckDB is not for high-concurrency OLTP (use Postgres). It's not distributed (use BigQuery/Snowflake/Spark for petabytes across many nodes). And it's optimized for read-heavy analytics, so you won't write rows one at a time — you'll insert in batches.

Code

Three patterns: query a file, query a DataFrame, persist to a database file·python
import duckdb
import pandas as pd

# 1. Query Parquet directly — no DataFrame in memory
result = duckdb.sql('''
    SELECT date_trunc('month', order_date) AS month,
           SUM(amount_usd) AS revenue
    FROM 'warehouse/orders/year=2026/month=*/*.parquet'
    GROUP BY 1 ORDER BY 1
''').to_df()

# 2. Query a Pandas DataFrame as if it were a table
df = pd.read_parquet('customers.parquet')
by_country = duckdb.sql('''
    SELECT country, COUNT(*) AS n FROM df GROUP BY 1 ORDER BY n DESC
''').to_df()

# 3. Persist to a DuckDB file — like a SQLite for analytics
con = duckdb.connect('analytics.duckdb')
con.sql('''
    CREATE OR REPLACE TABLE monthly_revenue AS
    SELECT date_trunc('month', order_date) AS month,
           SUM(amount_usd) AS revenue
    FROM 'warehouse/orders/year=2026/month=*/*.parquet'
    GROUP BY 1
''')
con.close()

External links

Exercise

Take any 100MB+ Parquet file (or a directory of partitioned Parquet). Write the same monthly-revenue (or equivalent) query three ways: pd.read_parquet + groupby, pl.scan_parquet + group_by, and duckdb.sql(...). Time each. Notice that DuckDB usually wins, and that the SQL is the most readable.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.