<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Thyne Ventures]]></title><description><![CDATA[Thyne Ventures]]></description><link>https://thyneventures.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 02 Nov 2026 23:02:58 GMT</lastBuildDate><atom:link href="https://thyneventures.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Is your Snowflake warehouse too big for its queries? One read-only query to check]]></title><description><![CDATA[Bigger warehouses double the credits per hour at each size step, but they only help when queries are large enough to use the extra compute. This read-only…]]></description><link>https://thyneventures.hashnode.dev/is-your-snowflake-warehouse-too-big-for-its-queries-one-read-only-query-to-check</link><guid isPermaLink="true">https://thyneventures.hashnode.dev/is-your-snowflake-warehouse-too-big-for-its-queries-one-read-only-query-to-check</guid><category><![CDATA[snowflake]]></category><category><![CDATA[SQL]]></category><category><![CDATA[data-engineering]]></category><category><![CDATA[finops]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Thyne Ventures]]></dc:creator><pubDate>Mon, 02 Nov 2026 15:19:43 GMT</pubDate><content:encoded><![CDATA[<p>Bigger warehouses double the credits per hour at each size step, but they only help when queries are large enough to use the extra compute. This read-only query looks at the last 14 days and shows, per warehouse and size, how much data typical queries scan and how long they run:</p>
<pre><code class="language-sql">SELECT warehouse_name,
       warehouse_size,
       COUNT(*) AS queries,
       ROUND(MEDIAN(bytes_scanned) / POWER(1024, 3), 3) AS median_gb_scanned,
       ROUND(APPROX_PERCENTILE(bytes_scanned, 0.9) / POWER(1024, 3), 3) AS p90_gb_scanned,
       ROUND(MEDIAN(execution_time) / 1000, 1) AS median_exec_s,
       SUM(IFF(bytes_spilled_to_local_storage &gt; 0, 1, 0)) AS spilling_queries
FROM snowflake.account_usage.query_history
WHERE start_time &gt;= DATEADD(day, -14, CURRENT_TIMESTAMP())
  AND warehouse_size IS NOT NULL
  AND execution_status = 'SUCCESS'
GROUP BY 1, 2
ORDER BY queries DESC;
</code></pre>
<h2>How to read it</h2>
<ul>
<li><strong>Large or bigger warehouse, p90 under ~1 GB scanned, median runtime a few seconds:</strong> most queries are too small to use the compute. Try one size down.</li>
<li><strong>No spilling queries:</strong> memory isn't the constraint, which makes downsizing lower risk.</li>
<li><strong>Spilling on the current size:</strong> leave it, or fix the spilling queries before resizing.</li>
</ul>
<h2>What to do about it</h2>
<ol>
<li>Drop one size on a single candidate: <code>ALTER WAREHOUSE &lt;name&gt; SET WAREHOUSE_SIZE = 'MEDIUM';</code></li>
<li>Re-run this query after a few days and compare median runtime. If it barely moved, you just halved that warehouse's credit rate.</li>
<li>Keep a separate larger warehouse for the few heavy jobs instead of sizing everything for them.</li>
</ol>
<p>Want a quick start first? The free <a href="https://thyneventures.gumroad.com/?utm_source=hashnode&amp;utm_campaign=sizing">Snowflake Slow Query Triage kit</a> has five read-only queries like this. The <a href="https://thyneventures.gumroad.com/l/rvmloh?utm_source=hashnode&amp;utm_campaign=sizing">Snowflake Query Performance Tuning Kit</a> adds pruning, spilling, queueing and idle-warehouse diagnostics with a guide to every result. Running cost, performance and security reviews together? The <a href="https://thyneventures.gumroad.com/l/mqqxze?utm_source=hashnode&amp;utm_campaign=sizing">Snowflake Complete Toolkit</a> bundles all three kits (32 read-only SQL files) for $69.</p>
]]></content:encoded></item><item><title><![CDATA[Are your Snowflake warehouses burning credits while idle? One read-only query to check]]></title><description><![CDATA[A warehouse bills every second it is running, whether or not a query is executing. A long AUTO_SUSPEND or a dashboard that pings every few minutes can keep…]]></description><link>https://thyneventures.hashnode.dev/are-your-snowflake-warehouses-burning-credits-while-idle-one-read-only-query-to-check</link><guid isPermaLink="true">https://thyneventures.hashnode.dev/are-your-snowflake-warehouses-burning-credits-while-idle-one-read-only-query-to-check</guid><category><![CDATA[snowflake]]></category><category><![CDATA[SQL]]></category><category><![CDATA[data-engineering]]></category><category><![CDATA[Cost Optimization]]></category><dc:creator><![CDATA[Thyne Ventures]]></dc:creator><pubDate>Sun, 01 Nov 2026 15:08:05 GMT</pubDate><content:encoded><![CDATA[<p>A warehouse bills every second it is running, whether or not a query is executing. A long AUTO_SUSPEND or a dashboard that pings every few minutes can keep it awake all day. This read-only query compares credits billed with time actually spent running queries over the last 14 days:</p>
<pre><code class="language-sql">WITH billed AS (
  SELECT warehouse_name,
         SUM(credits_used_compute) AS credits_billed
  FROM snowflake.account_usage.warehouse_metering_history
  WHERE start_time &gt;= DATEADD(day, -14, CURRENT_TIMESTAMP())
  GROUP BY 1
),
busy AS (
  SELECT warehouse_name,
         ROUND(SUM(execution_time) / 3.6e6, 2) AS query_hours,
         COUNT(*) AS queries
  FROM snowflake.account_usage.query_history
  WHERE start_time &gt;= DATEADD(day, -14, CURRENT_TIMESTAMP())
    AND warehouse_name IS NOT NULL
  GROUP BY 1
)
SELECT b.warehouse_name,
       ROUND(b.credits_billed, 2) AS credits_billed,
       COALESCE(q.query_hours, 0) AS query_hours,
       COALESCE(q.queries, 0)     AS queries
FROM billed b
LEFT JOIN busy q USING (warehouse_name)
ORDER BY credits_billed DESC;
</code></pre>
<p>Then check each warehouse's current setting:</p>
<pre><code class="language-sql">SHOW WAREHOUSES;
-- look at the auto_suspend column (seconds)
</code></pre>
<h2>How to read it</h2>
<ul>
<li><strong>Many credits, few query hours:</strong> the warehouse sits idle while billing. Look at its auto_suspend value first.</li>
<li><strong>auto_suspend of 600 or more:</strong> each wake-up can bill ten idle minutes. 60 seconds is a sensible default for most BI and ad-hoc warehouses.</li>
<li><strong>Lots of small queries all day:</strong> something is polling. Find it in query_history by user or client and slow it down.</li>
</ul>
<h2>What to do about it</h2>
<ol>
<li>Set <code>ALTER WAREHOUSE &lt;name&gt; SET AUTO_SUSPEND = 60;</code> on the worst offenders (test on one first).</li>
<li>Re-run the comparison a week later.</li>
<li>Move tiny scheduled jobs onto one shared small warehouse instead of keeping several awake.</li>
</ol>
<p>Want a quick start first? The free <a href="https://thyneventures.gumroad.com/?utm_source=hashnode&amp;utm_campaign=idle">Snowflake Slow Query Triage kit</a> has five read-only queries like this. The <a href="https://thyneventures.gumroad.com/l/rvmloh?utm_source=hashnode&amp;utm_campaign=idle">Snowflake Query Performance Tuning Kit</a> adds warehouse sizing, pruning, spilling and queueing diagnostics with a guide to every result.</p>
]]></content:encoded></item><item><title><![CDATA[Find your costliest Snowflake query patterns with one read-only query]]></title><description><![CDATA[Most Snowflake bills are driven by a handful of repeated queries. Find them before you resize anything. This read-only query groups the last 14 days of…]]></description><link>https://thyneventures.hashnode.dev/find-your-costliest-snowflake-query-patterns-with-one-read-only-query</link><guid isPermaLink="true">https://thyneventures.hashnode.dev/find-your-costliest-snowflake-query-patterns-with-one-read-only-query</guid><category><![CDATA[snowflake]]></category><category><![CDATA[data-engineering]]></category><category><![CDATA[SQL]]></category><dc:creator><![CDATA[Thyne Ventures]]></dc:creator><pubDate>Sat, 31 Oct 2026 14:07:02 GMT</pubDate><content:encoded><![CDATA[<p>Most Snowflake bills are driven by a handful of repeated queries. Find them before you resize anything. This read-only query groups the last 14 days of history by query pattern and ranks them by total warehouse time:</p>
<pre><code class="language-sql">SELECT query_parameterized_hash,
       ANY_VALUE(LEFT(query_text, 200))           AS sample_text,
       ANY_VALUE(warehouse_name)                  AS warehouse,
       COUNT(*)                                   AS runs,
       ROUND(SUM(total_elapsed_time) / 3.6e6, 2)  AS total_hours,
       ROUND(AVG(total_elapsed_time) / 1000, 1)   AS avg_seconds,
       ROUND(AVG(bytes_scanned) / POWER(1024, 3), 2) AS avg_gb_scanned
FROM snowflake.account_usage.query_history
WHERE start_time &gt;= DATEADD(day, -14, CURRENT_TIMESTAMP())
  AND warehouse_name IS NOT NULL
  AND execution_status = 'SUCCESS'
GROUP BY 1
ORDER BY total_hours DESC
LIMIT 25;
</code></pre>
<h2>How to read it</h2>
<ul>
<li><strong>High runs, low avg_seconds:</strong> a dashboard or job firing far more often than anyone needs. Cut the refresh rate or let the result cache serve it.</li>
<li><strong>Low runs, high avg_seconds:</strong> one heavy job. Check partition pruning and spilling on its query profile.</li>
<li><strong>High avg_gb_scanned:</strong> the query reads most of a big table. Add a filter on the clustering column or select fewer columns.</li>
</ul>
<h2>What to do about it</h2>
<ol>
<li>Fix the top three patterns first. They usually account for most of the hours.</li>
<li>Re-run the query a week later and compare total_hours.</li>
<li>Only then think about warehouse size.</li>
</ol>
<p>The <a href="https://thyneventures.gumroad.com/l/rvmloh?utm_source=hashnode&amp;utm_campaign=costly">Snowflake Query Performance Tuning Kit</a> includes this script plus 9 other read-only diagnostics (pruning, spilling, queueing, warehouse sizing) with a guide to what each result means.</p>
]]></content:encoded></item><item><title><![CDATA[Is your Snowflake warehouse queueing? One read-only query to check]]></title><description><![CDATA[Slow Snowflake dashboards aren't always slow queries. Often the query runs in two seconds but waits twenty in line because the warehouse is full. Here's a…]]></description><link>https://thyneventures.hashnode.dev/is-your-snowflake-warehouse-queueing-one-read-only-query-to-check</link><guid isPermaLink="true">https://thyneventures.hashnode.dev/is-your-snowflake-warehouse-queueing-one-read-only-query-to-check</guid><category><![CDATA[snowflake]]></category><category><![CDATA[data-engineering]]></category><category><![CDATA[SQL]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Thyne Ventures]]></dc:creator><pubDate>Thu, 29 Oct 2026 14:11:17 GMT</pubDate><content:encoded><![CDATA[<p>Slow Snowflake dashboards aren't always slow queries. Often the query runs in two seconds but waits twenty in line because the warehouse is full. Here's a read-only query that shows which warehouses queue, and when:</p>
<pre><code class="language-sql">SELECT warehouse_name,
       DATE_TRUNC('hour', start_time)         AS hour_start,
       ROUND(AVG(avg_running), 2)             AS avg_running,
       ROUND(AVG(avg_queued_load), 2)         AS avg_queued_load,
       ROUND(AVG(avg_queued_provisioning), 2) AS avg_queued_provisioning,
       ROUND(AVG(avg_blocked), 2)             AS avg_blocked
FROM snowflake.account_usage.warehouse_load_history
WHERE start_time &gt;= DATEADD(day, -7, CURRENT_TIMESTAMP())
GROUP BY 1, 2
HAVING AVG(avg_queued_load) &gt; 0 OR AVG(avg_blocked) &gt; 0
ORDER BY avg_queued_load DESC
LIMIT 100;
</code></pre>
<h2>How to read it</h2>
<ul>
<li><strong>avg_queued_load &gt; 0</strong> means queries waited because the warehouse was busy. If it clusters at the same hours every day, you have a concurrency problem.</li>
<li><strong>avg_queued_provisioning</strong> is time spent waiting for compute to start or resize. Frequent auto-suspend plus bursty traffic causes this.</li>
<li><strong>avg_blocked</strong> is waiting on locks, usually concurrent MERGE or UPDATE jobs hitting the same table.</li>
</ul>
<h2>What to do about it</h2>
<ol>
<li><strong>Queueing at peak, little spilling:</strong> a bigger warehouse won't help much. Raise MAX_CLUSTER_COUNT (multi-cluster, Enterprise edition) or move BI and ELT onto separate warehouses.</li>
<li><strong>Provisioning waits:</strong> lengthen AUTO_SUSPEND slightly on the busiest warehouse so it isn't cold-starting every few minutes.</li>
<li><strong>Blocked time:</strong> serialize the DML jobs that touch the same tables.</li>
<li><strong>No queueing and low load:</strong> the warehouse may be oversized. Try one size down and compare elapsed times.</li>
</ol>
<p>The <a href="https://thyneventures.gumroad.com/l/rvmloh?utm_source=hashnode&amp;utm_campaign=queueing">Snowflake Query Performance Tuning Kit</a> includes a second part of this script that gives every warehouse a sizing verdict (concurrency, memory, or possibly oversized) from 14 days of query history, plus 9 other read-only diagnostics.</p>
]]></content:encoded></item><item><title><![CDATA[Is your Snowflake query reading the whole table? Check partition pruning]]></title><description><![CDATA[Pruning is the biggest performance lever in Snowflake. A query that scans 2% of a table's micro-partitions instead of 100% is often 10-50x faster on the…]]></description><link>https://thyneventures.hashnode.dev/is-your-snowflake-query-reading-the-whole-table-check-partition-pruning</link><guid isPermaLink="true">https://thyneventures.hashnode.dev/is-your-snowflake-query-reading-the-whole-table-check-partition-pruning</guid><category><![CDATA[snowflake]]></category><category><![CDATA[SQL]]></category><category><![CDATA[data-engineering]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Thyne Ventures]]></dc:creator><pubDate>Tue, 27 Oct 2026 14:07:06 GMT</pubDate><content:encoded><![CDATA[<p>Pruning is the biggest performance lever in Snowflake. A query that scans 2% of a table's micro-partitions instead of 100% is often 10-50x faster on the same warehouse. This read-only query finds the ones that don't prune:</p>
<pre><code class="language-sql">SELECT query_id, warehouse_name, partitions_scanned, partitions_total,
       ROUND(100 * partitions_scanned / NULLIF(partitions_total, 0), 1) AS pct_scanned,
       ROUND(bytes_scanned / POWER(1024, 3), 2) AS gb_scanned,
       ROUND(total_elapsed_time / 1000, 1) AS elapsed_s,
       LEFT(query_text, 300) AS query_snippet
FROM snowflake.account_usage.query_history
WHERE start_time &gt;= DATEADD(day, -7, CURRENT_TIMESTAMP())
  AND UPPER(execution_status) = 'SUCCESS'
  AND query_type = 'SELECT'
  AND partitions_total &gt;= 1000
  AND partitions_scanned / NULLIF(partitions_total, 0) &gt; 0.8
ORDER BY partitions_scanned DESC
LIMIT 50;
</code></pre>
<p>A <code>pct_scanned</code> near 100 on a big table with a selective WHERE clause is the signal. Full scans are fine for genuine full-table jobs, so check the query text.</p>
<p><strong>The most common fix:</strong> filter directly on the column the data arrives in order of, and don't wrap it in a function.</p>
<pre><code class="language-sql">WHERE TO_DATE(event_ts) = '2026-01-01'                         -- prunes poorly
WHERE event_ts &gt;= '2026-01-01' AND event_ts &lt; '2026-01-02'     -- prunes well
</code></pre>
<p>Also filter the fact table directly instead of only through a join to a dimension. If the natural filter column isn't how the data was loaded, consider a clustering key or search optimization.</p>
<p>The <a href="https://thyneventures.gumroad.com/l/rvmloh?utm_source=hashnode&amp;utm_campaign=pruning">Snowflake Query Performance Tuning Kit</a> includes a per-table version of this check (via ACCESS_HISTORY) plus 9 other diagnostic scripts.</p>
]]></content:encoded></item><item><title><![CDATA[Find the Snowflake queries spilling to remote storage (one read-only query)]]></title><description><![CDATA[When a Snowflake query's intermediate results don't fit in warehouse memory, it spills: first to the warehouse's local SSD, then to remote cloud storage…]]></description><link>https://thyneventures.hashnode.dev/find-the-snowflake-queries-spilling-to-remote-storage-one-read-only-query</link><guid isPermaLink="true">https://thyneventures.hashnode.dev/find-the-snowflake-queries-spilling-to-remote-storage-one-read-only-query</guid><category><![CDATA[snowflake]]></category><category><![CDATA[SQL]]></category><category><![CDATA[data-engineering]]></category><dc:creator><![CDATA[Thyne Ventures]]></dc:creator><pubDate>Tue, 27 Oct 2026 00:06:25 GMT</pubDate><content:encoded><![CDATA[<p>When a Snowflake query's intermediate results don't fit in warehouse memory, it spills: first to the warehouse's local SSD, then to remote cloud storage. Remote spill often makes a query 5-10x slower, and it's easy to find.</p>
<pre><code class="language-sql">SELECT query_id, warehouse_name, warehouse_size,
       ROUND(total_elapsed_time / 1000, 1) AS elapsed_s,
       ROUND(bytes_scanned / POWER(1024, 3), 2) AS gb_scanned,
       ROUND(bytes_spilled_to_local_storage / POWER(1024, 3), 2) AS gb_spilled_local,
       ROUND(bytes_spilled_to_remote_storage / POWER(1024, 3), 2) AS gb_spilled_remote,
       ROUND((bytes_spilled_to_local_storage + bytes_spilled_to_remote_storage)
             / NULLIF(bytes_scanned, 0), 2) AS spill_ratio,
       LEFT(query_text, 300) AS query_snippet
FROM snowflake.account_usage.query_history
WHERE start_time &gt;= DATEADD(day, -7, CURRENT_TIMESTAMP())
  AND (bytes_spilled_to_local_storage &gt; 0 OR bytes_spilled_to_remote_storage &gt; 0)
ORDER BY bytes_spilled_to_remote_storage DESC, bytes_spilled_to_local_storage DESC
LIMIT 50;
</code></pre>
<p><strong>How to read it:</strong> <code>spill_ratio</code> is GB spilled divided by GB scanned. A ratio well above 1 usually means a join or aggregation is multiplying rows, not that the warehouse is too small.</p>
<p><strong>Fix it in this order:</strong></p>
<ol>
<li>Reduce the data: filter earlier, select fewer columns, pre-aggregate before joining, fix accidental many-to-many joins.</li>
<li>Drop unnecessary ORDER BY / DISTINCT / window functions over the full data set.</li>
<li>If the query is already lean, try the next warehouse size up and re-measure. If the remote spill disappears, the bigger size is often cheaper overall.</li>
<li>For memory-heavy workloads, consider a Snowpark-optimized warehouse.</li>
</ol>
<p>This is one of 10 diagnostic scripts in the <a href="https://thyneventures.gumroad.com/l/rvmloh?utm_source=devto&amp;utm_campaign=spill">Snowflake Query Performance Tuning Kit</a>, which also covers pruning, queueing, cache hit rates, exploding joins and clustering candidates. All read-only.</p>
<h2>Free download</h2>
<p>Free download: grab 5 more triage queries in the free Snowflake Slow Query Triage kit: <a href="https://thyneventures.gumroad.com/l/snowflake-slow-query-triage">https://thyneventures.gumroad.com/l/snowflake-slow-query-triage</a> . Want the full playbook? The Snowflake Query Performance Tuning Kit is 30% off with code LAUNCH30 until Thu Oct 29: <a href="https://thyneventures.gumroad.com/l/rvmloh">https://thyneventures.gumroad.com/l/rvmloh</a></p>
]]></content:encoded></item><item><title><![CDATA[Why is this Snowflake query slow? 3 ACCOUNT_USAGE queries that tell you]]></title><description><![CDATA["Just make the warehouse bigger" is the most expensive way to tune Snowflake, and often it doesn't even work. A bigger warehouse speeds up the execution…]]></description><link>https://thyneventures.hashnode.dev/why-is-this-snowflake-query-slow-3-account-usage-queries-that-tell-you</link><guid isPermaLink="true">https://thyneventures.hashnode.dev/why-is-this-snowflake-query-slow-3-account-usage-queries-that-tell-you</guid><category><![CDATA[snowflake]]></category><category><![CDATA[SQL]]></category><category><![CDATA[data-engineering]]></category><dc:creator><![CDATA[Thyne Ventures]]></dc:creator><pubDate>Mon, 26 Oct 2026 21:20:56 GMT</pubDate><content:encoded><![CDATA[<p>"Just make the warehouse bigger" is the most expensive way to tune Snowflake, and often it doesn't even work. A bigger warehouse speeds up the <em>execution</em> phase of a query. It does nothing for a query that spends its time compiling, waiting on a lock, or reading 100% of a table it only needed 2% of.</p>
<p>The good news is that Snowflake already records why each query was slow. It's all in <code>SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY</code>. Here are three read-only queries I use to separate "needs a bigger warehouse" from "needs a better query".</p>
<blockquote>
<p>You need a role with <code>IMPORTED PRIVILEGES</code> on the <code>SNOWFLAKE</code> database. <code>QUERY_HISTORY</code> can lag real time by up to about 45 minutes, and all times in it are in milliseconds.</p>
</blockquote>
<h2>1. Where does the time actually go?</h2>
<p>Every query's elapsed time breaks down into compile, queue, lock wait and execution. This query shows the 25 slowest queries of the week and names the phase that dominated.</p>
<pre><code class="language-sql">SELECT query_id,
       warehouse_name,
       warehouse_size,
       ROUND(total_elapsed_time / 1000, 1) AS elapsed_s,
       ROUND(compilation_time / 1000, 1)   AS compile_s,
       ROUND((queued_provisioning_time + queued_repair_time
              + queued_overload_time) / 1000, 1) AS queued_s,
       ROUND(transaction_blocked_time / 1000, 1) AS lock_wait_s,
       ROUND(execution_time / 1000, 1)     AS exec_s,
       CASE GREATEST(compilation_time,
                     queued_provisioning_time + queued_repair_time + queued_overload_time,
                     transaction_blocked_time, execution_time)
            WHEN execution_time   THEN 'EXECUTION'
            WHEN compilation_time THEN 'COMPILE'
            WHEN transaction_blocked_time THEN 'LOCK_WAIT'
            ELSE 'QUEUE'
       END AS dominant_phase,
       LEFT(query_text, 200) AS query_snippet
FROM snowflake.account_usage.query_history
WHERE start_time &gt;= DATEADD(day, -7, CURRENT_TIMESTAMP())
  AND UPPER(execution_status) = 'SUCCESS'
  AND warehouse_name IS NOT NULL
ORDER BY total_elapsed_time DESC
LIMIT 25;
</code></pre>
<p><strong>How to read it:</strong></p>
<ul>
<li><strong>QUEUE</strong> means the warehouse was full. That's a concurrency problem, so think multi-cluster or separate warehouses, not a bigger size.</li>
<li><strong>COMPILE</strong> means the SQL is hard to <em>plan</em>: giant generated statements, deep view stacks, or huge <code>IN</code> lists. Warehouse size is irrelevant here.</li>
<li><strong>LOCK_WAIT</strong> means concurrent DML on the same table. Serialize those jobs.</li>
<li><strong>EXECUTION</strong> is the only case where the next two queries (and possibly a bigger warehouse) come in.</li>
</ul>
<h2>2. Is it spilling?</h2>
<p>When a join or aggregation doesn't fit in memory, Snowflake spills to local disk and then to remote storage. Remote spilling is where queries go from seconds to many minutes.</p>
<pre><code class="language-sql">SELECT query_id,
       warehouse_name,
       warehouse_size,
       ROUND(total_elapsed_time / 1000, 1)                        AS elapsed_s,
       ROUND(bytes_scanned / POWER(1024, 3), 2)                   AS gb_scanned,
       ROUND(bytes_spilled_to_local_storage / POWER(1024, 3), 2)  AS gb_spilled_local,
       ROUND(bytes_spilled_to_remote_storage / POWER(1024, 3), 2) AS gb_spilled_remote,
       LEFT(query_text, 200)                                      AS query_snippet
FROM snowflake.account_usage.query_history
WHERE start_time &gt;= DATEADD(day, -7, CURRENT_TIMESTAMP())
  AND (bytes_spilled_to_local_storage &gt; 0 OR bytes_spilled_to_remote_storage &gt; 0)
ORDER BY bytes_spilled_to_remote_storage DESC, bytes_spilled_to_local_storage DESC
LIMIT 25;
</code></pre>
<p><strong>How to read it:</strong> compare <code>gb_spilled_*</code> with <code>gb_scanned</code>. If a query spills far <em>more</em> than it scanned, something is multiplying rows. That's usually a join on a non-unique key, so check the join before you touch the warehouse. If the query is already lean, try one size up and re-measure. When remote spilling disappears, the larger size often costs <em>less</em> in total because it finishes so much faster.</p>
<h2>3. Is it pruning?</h2>
<p>Snowflake stores tables in micro-partitions and skips the ones a filter rules out. That's pruning, and it's the single biggest performance lever you have. This query finds SELECTs on large tables that read more than 80% of the partitions anyway.</p>
<pre><code class="language-sql">SELECT query_id,
       warehouse_name,
       partitions_scanned,
       partitions_total,
       ROUND(100 * partitions_scanned / NULLIF(partitions_total, 0), 1) AS pct_scanned,
       ROUND(total_elapsed_time / 1000, 1) AS elapsed_s,
       LEFT(query_text, 200) AS query_snippet
FROM snowflake.account_usage.query_history
WHERE start_time &gt;= DATEADD(day, -7, CURRENT_TIMESTAMP())
  AND query_type = 'SELECT'
  AND partitions_total &gt;= 1000
  AND partitions_scanned / NULLIF(partitions_total, 0) &gt; 0.8
ORDER BY partitions_scanned DESC
LIMIT 25;
</code></pre>
<p><strong>How to read it:</strong> read the WHERE clause of each query. The classic culprit is wrapping the filter column in a function:</p>
<pre><code class="language-sql">-- prunes poorly
WHERE TO_DATE(event_ts) = '2026-10-01'
-- prunes well
WHERE event_ts &gt;= '2026-10-01' AND event_ts &lt; '2026-10-02'
</code></pre>
<p>If the filter is already clean and the table is large and read far more often than it's written, the table may be a candidate for a clustering key.</p>
<h2>What these queries can't tell you</h2>
<p><code>QUERY_HISTORY</code> reports one row per query, so it can't tell you <em>which</em> join exploded or <em>which</em> table in a five-way join failed to prune. For that, open the Query Profile in Snowsight, or run <code>GET_QUERY_OPERATOR_STATS('&lt;query_id&gt;')</code>. It returns input and output rows for every operator, and it works for any query from the last 14 days. Use the three queries above to decide where to look, then use the profile to find the exact operator.</p>
<h2>Tune patterns, not single queries</h2>
<p>Once you know <em>what kind</em> of slow you're dealing with, group by <code>query_parameterized_hash</code> instead of <code>query_id</code>. A 15-second dashboard query that runs 4,000 times a day usually matters more than one 30-minute monster. Fix the top three patterns, tag them with <code>QUERY_TAG</code>, and re-run these queries a week later to confirm the improvement.</p>
<hr />
<p><em>Disclosure: I sell a paid kit built on these ideas. The</em> <em><strong>Snowflake Query Performance Tuning Kit</strong></em> <em>has 10 read-only scripts that also cover queueing and warehouse sizing, cache hit rates, compile-heavy patterns, exploding joins (with per-join row counts), clustering candidates, Query Acceleration eligibility and failed/timed-out queries, plus a fix playbook:</em> <a href="https://thyneventures.gumroad.com/l/rvmloh"><em>https://thyneventures.gumroad.com/l/rvmloh</em></a><em>. The three queries above are free to use however you like. Not affiliated with Snowflake Inc.</em></p>
<h2>Free download</h2>
<p>Free download: grab 5 more triage queries in the free Snowflake Slow Query Triage kit: <a href="https://thyneventures.gumroad.com/l/snowflake-slow-query-triage">https://thyneventures.gumroad.com/l/snowflake-slow-query-triage</a> . Want the full playbook? The Snowflake Query Performance Tuning Kit is 30% off with code LAUNCH30 until Thu Oct 29: <a href="https://thyneventures.gumroad.com/l/rvmloh">https://thyneventures.gumroad.com/l/rvmloh</a></p>
]]></content:encoded></item></channel></rss>