Open source · MIT · Snowflake + BigQuery

See what could run on one machine.

ducklens reads your warehouse query history and works out how much of the bill could run on a single DuckDB machine. It goes query by query, decides each one based on how much it spilled to disk rather than how much it scanned, and rolls the results up into a move, split, or keep call per warehouse, reconciled to your invoice. It runs on your laptop and never sees a credential.

View on GitHub -> See a sample report
# no account needed: synthetic data, full audit
pipx install ducklens
ducklens demo

# or score your own read-only export, locally
ducklens audit --source snowflake --query-history qh.parquet \
  --metering m.parquet --metering-daily md.parquet --format html

The idea

Why it looks at how much a query spilled.

DuckDB is an out-of-core engine. A query that scans two terabytes but just filters and aggregates them runs fine on a machine with a few gigabytes of memory, because it streams through and spills to disk when it needs to. What actually breaks a single machine is a query whose working set outgrows memory, and that often has little to do with how much it scanned. So ducklens decides based on how much each query spilled, which is the thing that matters, and it never counts a large scan against a query on its own.

How it scores

How it decides what fits.

01

Spill decides it

A query is held back if it spilled to remote storage, or spilled more to local disk than the target machine has memory for. A large scan on its own never holds a query back.

02

Real concurrency only

Sixteen quick dashboard pings on page load don't count, but sixteen analysts each running a 30-second query at once do. It only counts overlap between queries that ran long enough to matter.

03

One reason each

Non-portable SQL, write transactions, and high-frequency writes each keep a query on Snowflake. Every held-back query is blamed on a single reason, so the dollars don't double-count.

Cost comes from your metered credits, spread across queries by runtime and calibrated so the per-query numbers add back up to what you were billed. The headline is anchored to METERING_DAILY_HISTORY. Idle warehouse time and serverless spend are shown as their own lines, kept out of the movable number. On BigQuery it switches to bytes billed. All of it is one SQL file you can read: scoring.sql.

Run it on real data

You don't need an account to try it.

# a real analytical workload, generated locally from TPC-H
python scripts/tpch_to_history.py --sf 8 --days 90 --ram-gb 8 --out ./tpch
ducklens audit --source snowflake \
  --query-history ./tpch/query_history.parquet \
  --metering ./tpch/warehouse_metering_history.parquet \
  --metering-daily ./tpch/metering_daily_history.parquet --ram-gb 8

# or reproduce the Snowset result on a public trace of real queries
# (mapping SQL ships in ducklens/export_sql/snowset_to_history.sql)

Tested on Snowset

Snowset is a public trace of about 70 million real Snowflake queries. It records real spill bytes per query, which is what the scorer needs.

5,840,605queries across 1,290 warehouses
~20 sto score them all
81%of query compute fit on one machine
Read the write-up ->

Free tool, paid assessment

It's free to run yourself. The invoice-reconciled version is the assessment.

The tool is free and MIT-licensed, and it stays that way. You run a read-only export, ducklens reads the files locally, and nothing leaves your machine. If you want the version reconciled to your real invoice, with a written recommendation on what to move and what to keep and someone accountable for it, that's the fixed-fee Cost-Fit Assessment.

See the assessment -> See a sample report