Open source · MIT · Snowflake + BigQuery
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.
# 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
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
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.
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.
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
# 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.
Free tool, paid 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.