← all posts

How I cut a Snowflake bill by reading the query history

The query history table already knows where the money goes. You only have to ask it.

A warehouse bill grows in small steps. Nobody notices a single expensive query. Everybody notices the invoice.

Start with the query history

Snowflake keeps every query in SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY. Group by the text of the query and sort by total time:

SELECT
  LEFT(query_text, 80) AS query,
  COUNT(*) AS runs,
  SUM(total_elapsed_time) / 1000 / 60 AS minutes
FROM snowflake.account_usage.query_history
WHERE start_time > DATEADD(day, -30, CURRENT_TIMESTAMP)
GROUP BY 1
ORDER BY minutes DESC
LIMIT 20;

What the list showed

  • One dashboard refreshed a full table scan every five minutes.
  • A dbt model rebuilt a year of history on every run.
  • A forgotten scheduled task copied a table to itself.

The fixes

Each fix took less than a day:

  1. Cache the dashboard query for one hour.
  2. Make the dbt model incremental.
  3. Delete the task.

The bill fell by about a third. The query history had the answer the whole time.

[03] contact

Let's talk data.