<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Data Today: Snowflake</title>
  <subtitle>Field notes for enterprise data engineers and scientists.</subtitle>
  <link href="https://data-today.net/snowflake/feed.xml" rel="self" />
  <link href="https://data-today.net/" />
  <updated>2026-06-07T00:00:00Z</updated>
  <id>https://data-today.net/</id>
  <author>
    <name>Data Today Newsroom</name>
  </author>
  <entry>
    <title>Snowflake warehouse sizing: stop paying for idle compute</title>
    <link href="https://data-today.net/snowflake/snowflake-warehouse-sizing/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-warehouse-sizing/</id>
    <content type="html">&lt;p&gt;If your Snowflake bill jumped last quarter and nobody changed the data, the culprit is almost always compute, and almost always a warehouse that is bigger or busier than the work needs. A Snowflake virtual warehouse is just a cluster you rent by the second, and its size is the single dial that sets how fast credits drain. Get the dial wrong and you either throttle every analyst or you torch budget on idle compute. &lt;strong&gt;An XS warehouse burns 1 credit per hour; a 4XL burns 128 for the same wall-clock hour.&lt;/strong&gt; That is a 128x spread on one setting, and most teams pick it once and never revisit it.&lt;/p&gt;
&lt;p&gt;This guide is for the person who owns the warehouse and answers to finance when the credit line spikes. The goal is to size by workload, not by reflex, and to prove the change with numbers you can pull from your own account.&lt;/p&gt;
&lt;h2 id=&quot;how-does-warehouse-size-actually-behave&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/#how-does-warehouse-size-actually-behave&quot;&gt;&lt;span&gt;How does warehouse size actually behave?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake sizes go XS, S, M, L, XL, then 2XL through 6XL. Each step up doubles the compute, and it doubles the credit rate in lockstep. The pricing is not a curve you have to model; it is a clean power of two.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-warehouse-sizing-fig-credits.png&quot; alt=&quot;Bar chart of Snowflake credits per hour by warehouse size: XS 1, S 2, M 4, L 8, XL 16, 2XL 32, 3XL 64, 4XL 128&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Credits per hour double with every Snowflake warehouse size, from 1 at XS to 128 at 4XL. Source: Snowflake documentation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The trap is assuming bigger is wasteful and smaller is safe. It is the opposite as often as not. A larger warehouse finishes a heavy query faster, and because billing is per-second after the first 60 seconds, a query that runs in 2 minutes on an L can cost the same as one that crawls for 8 minutes on an S. The size that wins is the smallest one that does not spill to disk and does not queue. Doubling the size only saves money when it more than halves the runtime, which holds for large scans and big joins but breaks for small, serial, or metadata-bound queries.&lt;/p&gt;
&lt;p&gt;You can see the difference in the query profile. Two signals tell you a warehouse is too small for the job:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Spilling.&lt;/strong&gt; When a query runs out of memory it spills to local then remote storage, and remote spill is brutally slow. Any remote spill is a sign to size up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Queuing.&lt;/strong&gt; If queries wait for a slot, the warehouse is saturated. That is a concurrency problem, not a size problem, and the fix is different.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-does-it-cost-and-where-does-it-break&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/#what-does-it-cost-and-where-does-it-break&quot;&gt;&lt;span&gt;What does it cost, and where does it break?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sizing up fixes spilling. It does nothing for queuing, because a single larger cluster still runs a fixed number of concurrent queries before it starts holding them in a line. The right tool for a crowd of small queries is &lt;strong&gt;multi-cluster scaling&lt;/strong&gt;: keep the size modest and let Snowflake add clusters under concurrency, then retire them when the rush passes. Reach for a bigger size when one query is slow; reach for more clusters when many queries are waiting.&lt;/p&gt;
&lt;p&gt;Here is the comparison that matters when you are deciding which lever to pull:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Right lever&lt;/th&gt;
&lt;th&gt;Wrong lever&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One query spills to remote disk&lt;/td&gt;
&lt;td&gt;Size up one step&lt;/td&gt;
&lt;td&gt;Add clusters&lt;/td&gt;
&lt;td&gt;Extra clusters do not give a single query more memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Many short queries queue at 9am&lt;/td&gt;
&lt;td&gt;Multi-cluster (min 1, max 3)&lt;/td&gt;
&lt;td&gt;Size up&lt;/td&gt;
&lt;td&gt;A bigger single cluster still serializes the crowd&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warehouse runs all day at 5% load&lt;/td&gt;
&lt;td&gt;Auto-suspend at 60s&lt;/td&gt;
&lt;td&gt;Bigger warehouse&lt;/td&gt;
&lt;td&gt;You are paying for idle, not for slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nightly batch runs 40 minutes&lt;/td&gt;
&lt;td&gt;Size up, measure cost&lt;/td&gt;
&lt;td&gt;Leave it on an S&lt;/td&gt;
&lt;td&gt;Faster finish can cost the same and frees the window&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The most expensive mistake is not the wrong size at all. It is idle time. A warehouse left running with no queries bills every second until it suspends. Set &lt;strong&gt;auto-suspend to 60 seconds&lt;/strong&gt; for interactive warehouses and confirm auto-resume is on so the next query wakes it. The classic 600-second default means each abandoned warehouse quietly bills ten minutes of nothing, over and over.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-roll-it-out-without-guessing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/#how-do-i-roll-it-out-without-guessing&quot;&gt;&lt;span&gt;How do I roll it out without guessing?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Do not size by vibes. Snowflake records every query and every credit in &lt;code&gt;ACCOUNT_USAGE&lt;/code&gt;, so you can measure the real distribution before you touch anything. Start by finding your spillers, because those are where sizing up pays for itself:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Queries that spilled to remote storage in the last 7 days,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- ranked by how much they spilled. These are your size-up candidates.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
    warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    query_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;ROUND&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bytes_spilled_to_remote_storage &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; POWER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; remote_spill_gb&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;ROUND&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;total_elapsed_time &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; elapsed_s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query_text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; query_preview
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; snowflake&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account_usage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;query_history
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; start_time &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; DATEADD&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;day&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; bytes_spilled_to_remote_storage &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; remote_spill_gb &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then look at the other end: warehouses that bill credits while doing almost nothing. Pair the credit spend from &lt;code&gt;WAREHOUSE_METERING_HISTORY&lt;/code&gt; with the query counts from &lt;code&gt;QUERY_HISTORY&lt;/code&gt;, and any warehouse with high credits and low query volume is an auto-suspend problem, not a sizing one.&lt;/p&gt;
&lt;p&gt;Once you have the data, roll out in three controlled moves:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Set guardrails first.&lt;/strong&gt; Put a &lt;code&gt;RESOURCE MONITOR&lt;/code&gt; on each warehouse with a monthly credit quota and a suspend trigger, so a runaway query or a forgotten session cannot run up an open-ended bill. This is your seatbelt before you start changing sizes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Change one warehouse, then measure.&lt;/strong&gt; Resize a single warehouse with &lt;code&gt;ALTER WAREHOUSE ... SET WAREHOUSE_SIZE&lt;/code&gt;, leave it for a few days, and compare credits and median runtime against the week before. Changing everything at once means you learn nothing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Split workloads.&lt;/strong&gt; Stop running dashboards, ad-hoc analysis, and heavy ELT through one shared warehouse. Give each workload its own warehouse so you can size and monitor them independently, and so a 3XL backfill never starves the analyst running a quick count.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The rollback is trivial, which is why this is safe to try: resizing takes effect on the next query, and you can drop back a size in one statement if the cost does not move the way you expected.&lt;/p&gt;
&lt;p&gt;If you run dbt or scheduled ELT, point those at their own warehouse and size it for the heaviest model in the run, not the average. Batch work is exactly where a larger warehouse earns its credits, because it finishes faster and hands the time window back. The rest of the &lt;a href=&quot;https://data-today.net/snowflake/&quot;&gt;Snowflake guides&lt;/a&gt; go deeper on the pipeline and governance side.&lt;/p&gt;
&lt;h2 id=&quot;the-one-number-to-watch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/#the-one-number-to-watch&quot;&gt;&lt;span&gt;The one number to watch&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Track credits per active query-hour, not raw credits. Raw credits go up when usage grows, which can be healthy. Credits burned per hour of actual query work is the number that exposes idle warehouses and oversized clusters, and it is the one that drops the day you right-size. Pull it weekly, watch the trend, and let the warehouse that does the least work for the most credits be the first one you fix.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-overview&quot;&gt;Snowflake Documentation: Virtual warehouses and warehouse sizes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/query_history&quot;&gt;Snowflake Documentation: ACCOUNT_USAGE QUERY_HISTORY view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/resource-monitors&quot;&gt;Snowflake Documentation: Working with resource monitors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Dynamic Tables vs Streams and Tasks: which Snowflake pipeline to build</title>
    <link href="https://data-today.net/snowflake/snowflake-pipelines-streams-tasks/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-pipelines-streams-tasks/</id>
    <content type="html">&lt;p&gt;Most Snowflake data teams hit the same fork. You have raw data landing in a table and you need a clean, transformed version that stays current. Do you write the transformation as a declarative &lt;strong&gt;Dynamic Table&lt;/strong&gt; and let Snowflake keep it fresh, or do you wire up a &lt;strong&gt;Stream&lt;/strong&gt; to capture changes and a &lt;strong&gt;Task&lt;/strong&gt; to process them on a schedule you control? Pick wrong and you either fight the orchestration you did not need or hit a freshness wall you did not see coming. The single hard number that settles a lot of these arguments: &lt;strong&gt;Dynamic Tables cannot refresh faster than a 60-second target lag.&lt;/strong&gt; If your SLA is tighter than a minute, that choice is already made for you.&lt;/p&gt;
&lt;p&gt;This guide is for the engineer designing a transformation pipeline on Snowflake who wants to stop relitigating the same build-versus-declare debate on every table. We will use real Snowflake behavior, not vibes.&lt;/p&gt;
&lt;h2 id=&quot;what-is-each-one-actually-doing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-pipelines-streams-tasks/#what-is-each-one-actually-doing&quot;&gt;&lt;span&gt;What is each one actually doing?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;Dynamic Table&lt;/strong&gt; is a materialized result of a &lt;code&gt;SELECT&lt;/code&gt; that Snowflake keeps up to date for you. You write the query and a &lt;code&gt;TARGET_LAG&lt;/code&gt;, and Snowflake figures out the dependency graph, watches the base tables, and refreshes, incrementally when it can, so readers never see a partial result.&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; DYNAMIC &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; dt_orders
    TARGET_LAG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;10 minutes&#39;&lt;/span&gt;
    WAREHOUSE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transform_wh
    REFRESH_MODE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; INCREMENTAL
&lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; order_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; customer_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; order_date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
           TRIM&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UPPER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;product_name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; product_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
           quantity &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; unit_price &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; line_total
    &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; raw_orders
    &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; order_status &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;returned&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the whole pipeline. No scheduler, no change-tracking code. Set &lt;code&gt;TARGET_LAG = &#39;10 minutes&#39;&lt;/code&gt; and Snowflake tries to keep the table no more than ten minutes behind its source. Chain dynamic tables that read from each other and Snowflake refreshes them in dependency order against a consistent snapshot, which is the part that makes them genuinely pleasant for multi-step transforms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Streams and Tasks&lt;/strong&gt; are the imperative alternative. A Stream is a change-tracking cursor over a table: it records the rows inserted, updated, or deleted since you last consumed it. A Task runs a SQL statement (or calls a procedure) on a schedule or when a predecessor finishes. You compose them yourself: a Stream captures what changed, a Task reads the Stream and applies the change with a &lt;code&gt;MERGE&lt;/code&gt;. You own the logic, the ordering, and the failure handling.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-pipelines-streams-tasks-fig.png&quot; alt=&quot;Horizontal bar chart of lowest practical lag by Snowflake approach: Snowpipe Streaming about 10 seconds, Streams plus Tasks 60 seconds, Dynamic Tables 60-second minimum, scheduled hourly task 3,600 seconds, on a log scale&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: the lowest practical lag each Snowflake approach reaches. Dynamic Tables and minute-level Tasks both bottom out near 60 seconds; Snowpipe Streaming goes lower; an hourly task sits at 3,600. Source: Snowflake documentation on dynamic tables and tasks.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;which-one-should-i-reach-for&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-pipelines-streams-tasks/#which-one-should-i-reach-for&quot;&gt;&lt;span&gt;Which one should I reach for?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The honest answer is that Dynamic Tables are the right default for most analytical transforms now, and Streams and Tasks are the tool you keep for the cases Dynamic Tables cannot express. Snowflake&#39;s own rule of thumb is blunt: if your logic fits in a &lt;code&gt;SELECT&lt;/code&gt;, it is a candidate for a Dynamic Table.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reach for Dynamic Tables when&lt;/strong&gt; the transform is expressible as SQL, you want declarative freshness you tune with one parameter, and a minute or more of lag is fine. This is the bulk of cleaning, joining, and aggregating work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reach for Streams and Tasks when&lt;/strong&gt; you need procedural logic (calling a stored procedure, an external function, branching), sub-minute freshness, or fine control over exactly when and how a change is applied. CDC into a slowly changing dimension with custom merge rules is the classic case.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reach for Snowpipe Streaming when&lt;/strong&gt; the requirement is genuinely low-latency ingestion, rows available in seconds, which neither of the above delivers on its own.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A practical gotcha sits inside the freshness column: a Task scheduled &amp;quot;every 1 minute&amp;quot; is not the same as one-minute freshness. The task has to start, the warehouse has to resume if it was suspended, and the merge has to run, so real end-to-end lag is the schedule plus the run time. Snowflake&#39;s triggered tasks, which fire when an underlying Stream gets data instead of on a fixed clock, close most of that gap and are usually the better choice than a tight cron when you want responsiveness without polling an empty stream every minute.&lt;/p&gt;
&lt;p&gt;Here is the comparison that actually drives the decision:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Dynamic Tables&lt;/th&gt;
&lt;th&gt;Streams + Tasks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Programming model&lt;/td&gt;
&lt;td&gt;Declarative: write a SELECT&lt;/td&gt;
&lt;td&gt;Imperative: you orchestrate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lowest freshness&lt;/td&gt;
&lt;td&gt;60-second target lag minimum&lt;/td&gt;
&lt;td&gt;Down to ~1 minute on a schedule, faster with triggered tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-step pipelines&lt;/td&gt;
&lt;td&gt;Auto dependency graph, consistent snapshot&lt;/td&gt;
&lt;td&gt;You sequence tasks yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stored procedures / external functions&lt;/td&gt;
&lt;td&gt;Not supported in the definition&lt;/td&gt;
&lt;td&gt;Fully supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure handling&lt;/td&gt;
&lt;td&gt;Managed by Snowflake&lt;/td&gt;
&lt;td&gt;Yours to design and monitor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Cleaning, joins, aggregations&lt;/td&gt;
&lt;td&gt;CDC, custom merge logic, procedural steps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;what-does-it-cost-and-where-does-it-bite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-pipelines-streams-tasks/#what-does-it-cost-and-where-does-it-bite&quot;&gt;&lt;span&gt;What does it cost, and where does it bite?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Both approaches bill the same underlying things, so cost is rarely the deciding factor, but the shape differs. A Dynamic Table charges &lt;strong&gt;warehouse compute&lt;/strong&gt; for each refresh query, &lt;strong&gt;Cloud Services&lt;/strong&gt; for the dependency tracking and change detection, and &lt;strong&gt;storage&lt;/strong&gt; for the materialized rows plus Time Travel. The trap is &lt;strong&gt;target lag&lt;/strong&gt;: a shorter lag means more frequent refreshes and more scheduling overhead, so setting &lt;code&gt;TARGET_LAG = &#39;1 minute&#39;&lt;/code&gt; on a table nobody reads more than hourly just burns credits for freshness no one consumes. Match the lag to how fresh the data genuinely needs to be, and use &lt;code&gt;TARGET_LAG = DOWNSTREAM&lt;/code&gt; on intermediate tables so they only refresh when something downstream needs them.&lt;/p&gt;
&lt;p&gt;Streams and Tasks bill the warehouse (or serverless compute) for each task run. The classic waste here is a frequent schedule on a Stream that is usually empty: guard every task with &lt;code&gt;WHEN SYSTEM$STREAM_HAS_DATA(&#39;my_stream&#39;)&lt;/code&gt; so it skips the run, and the credits, when nothing changed.&lt;/p&gt;
&lt;p&gt;If you run dbt, this maps cleanly: dbt can materialize models as Dynamic Tables, so you get declarative freshness inside your existing project rather than hand-rolling tasks. Point that work at its own warehouse, sized for the heaviest refresh, as covered in the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/&quot;&gt;warehouse sizing guide&lt;/a&gt;. The other &lt;a href=&quot;https://data-today.net/snowflake/&quot;&gt;Snowflake guides&lt;/a&gt; go deeper on cost monitoring.&lt;/p&gt;
&lt;h2 id=&quot;the-rule-that-saves-the-most-rework&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-pipelines-streams-tasks/#the-rule-that-saves-the-most-rework&quot;&gt;&lt;span&gt;The rule that saves the most rework&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start declarative, escalate only when blocked. Build the table as a Dynamic Table with a target lag that matches the real SLA. If you hit something a &lt;code&gt;SELECT&lt;/code&gt; cannot express, or you need freshness under a minute, drop that one table down to Streams and Tasks. Choosing imperative orchestration for a whole warehouse of tables you could have declared is the most common way teams sign up for maintenance they never needed.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-pipelines-streams-tasks/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables-about&quot;&gt;Snowflake Documentation: Dynamic tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/decision-guide&quot;&gt;Snowflake Documentation: Decision guide for dynamic tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/streams-intro&quot;&gt;Snowflake Documentation: Introduction to Streams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tasks-intro&quot;&gt;Snowflake Documentation: Introduction to Tasks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake clustering: when a clustering key actually pays off</title>
    <link href="https://data-today.net/snowflake/snowflake-performance-clustering/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-performance-clustering/</id>
    <content type="html">&lt;p&gt;When a Snowflake query is slow, the instinct is to size up the warehouse. Sometimes that is right. Often the real problem is that the query is reading the whole table to answer a question about a sliver of it, and no amount of extra compute fixes a full scan, it just pays for it faster. The fix is &lt;strong&gt;pruning&lt;/strong&gt;: getting Snowflake to skip the storage that cannot contain your answer. A clustering key is the main lever you have over how well that pruning works, and on the right table it is the difference between scanning &lt;strong&gt;9,800 micro-partitions and scanning 140&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This guide is for the data engineer who owns a large, slow table and a query profile that says &amp;quot;partitions scanned&amp;quot; is close to &amp;quot;partitions total&amp;quot;. The goal is to know when a clustering key earns its credits, and when it just quietly bills you for nothing.&lt;/p&gt;
&lt;h2 id=&quot;how-does-snowflake-decide-what-to-skip&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-performance-clustering/#how-does-snowflake-decide-what-to-skip&quot;&gt;&lt;span&gt;How does Snowflake decide what to skip?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every Snowflake table is silently split into &lt;strong&gt;micro-partitions&lt;/strong&gt;, contiguous chunks holding 50 to 500 MB of uncompressed data each, stored column by column. For every micro-partition, Snowflake keeps metadata: the min and max value of each column, the distinct count, and more. That metadata is the whole game. When you filter &lt;code&gt;WHERE event_date = &#39;2026-06-01&#39;&lt;/code&gt;, Snowflake checks each micro-partition&#39;s stored range for &lt;code&gt;event_date&lt;/code&gt; and skips any whose range cannot contain that date. Per Snowflake&#39;s own docs, a query touching 10% of a value range should ideally scan only 10% of the micro-partitions.&lt;/p&gt;
&lt;p&gt;Pruning only works when the values you filter on are physically grouped together. Data lands in micro-partitions in roughly the order you load it. If you load by day, rows for one day already sit together and a date filter prunes beautifully for free. If you load in random order, every micro-partition holds a smear of every date, no range can be ruled out, and the query reads everything even though it returns almost nothing.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-performance-clustering-fig.png&quot; alt=&quot;Bar chart of micro-partitions scanned for a one-day query: 9,800 when unclustered, 140 when clustered on event_date&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: clustering a large event table on its date column lets a one-day query prune from 9,800 micro-partitions down to 140. Source: Snowflake documentation on micro-partitions and pruning.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;A clustering key tells Snowflake to keep the table physically sorted on the columns you actually filter by, so that smear never forms. You can check how good the current grouping is without changing anything:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- How well is this table clustered on the column you filter by?&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- Lower average_depth = better pruning. A high depth on a big table&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- that you filter by event_date is the signal a clustering key may help.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; SYSTEM$CLUSTERING_INFORMATION&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;events&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;(event_date)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The number that matters in the result is &lt;strong&gt;clustering depth&lt;/strong&gt;: the average number of overlapping micro-partitions for that column. Depth near 1 means almost no overlap and excellent pruning. A large depth means heavy overlap and wasted scans.&lt;/p&gt;
&lt;p&gt;Clustering is not the only pruning lever, and reaching for it reflexively is a mistake. If your slow queries are highly selective point lookups, &lt;code&gt;WHERE customer_id = 12345&lt;/code&gt; against a huge table, the &lt;strong&gt;Search Optimization Service&lt;/strong&gt; often fits better: it builds a separate search-access index that prunes for equality and substring filters without physically reordering the table. It bills its own credits too, so the evaluation discipline is identical, but the two solve different shapes of problem. Clustering wins on range and date filters that scan a contiguous slice; search optimization wins on needle-in-haystack lookups across the whole table.&lt;/p&gt;
&lt;h2 id=&quot;what-does-a-clustering-key-cost-and-where-does-it-break&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-performance-clustering/#what-does-a-clustering-key-cost-and-where-does-it-break&quot;&gt;&lt;span&gt;What does a clustering key cost, and where does it break?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A clustering key is not free, and this is where teams get burned. Once you set one with &lt;code&gt;ALTER TABLE events CLUSTER BY (event_date)&lt;/code&gt;, Snowflake&#39;s &lt;strong&gt;automatic clustering&lt;/strong&gt; service reorganizes micro-partitions in the background to keep the table sorted as new data arrives. That background work is serverless compute, and it bills credits that show up in &lt;code&gt;AUTOMATIC_CLUSTERING_HISTORY&lt;/code&gt;, separate from your warehouses. The more the table churns, the more reclustering it triggers, and the more you pay.&lt;/p&gt;
&lt;p&gt;That cost profile decides where clustering wins and where it loses money:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table profile&lt;/th&gt;
&lt;th&gt;Clustering key?&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Large, filtered by one date/ID column, append-mostly&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Pruning savings dwarf the steady reclustering cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Small (under a few GB)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Snowflake already prunes it well; you would pay to reorder nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-churn, rows updated all over the key&lt;/td&gt;
&lt;td&gt;Rarely&lt;/td&gt;
&lt;td&gt;Constant reclustering can cost more than the queries save&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filtered by many different columns each query&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;One key cannot serve every filter; pick the dominant one or none&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two rules keep you out of trouble. First, &lt;strong&gt;cluster on low-cardinality-to-medium columns you filter on&lt;/strong&gt;, like a date or a region, not a unique ID with billions of values, because an ultra-high-cardinality key forces near-constant reordering. Second, do not cluster a table that fits in a handful of micro-partitions; Snowflake prunes small tables fine on its own and the service would bill you to sort data that was never the bottleneck.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-roll-it-out-without-guessing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-performance-clustering/#how-do-i-roll-it-out-without-guessing&quot;&gt;&lt;span&gt;How do I roll it out without guessing?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Prove the need before you turn anything on, then measure the bill after.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Confirm the table is actually scan-bound.&lt;/strong&gt; Open the query profile for the slow query and compare &amp;quot;partitions scanned&amp;quot; to &amp;quot;partitions total&amp;quot;. If you are scanning most of the table to return a small result, pruning is failing and clustering is a real candidate. If the scan is already small, your problem is elsewhere (a join, spilling, or a missing filter) and a clustering key will not help.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Baseline, then enable on one table.&lt;/strong&gt; Record the query runtime and the &lt;code&gt;SYSTEM$CLUSTERING_INFORMATION&lt;/code&gt; depth. Set the key with &lt;code&gt;ALTER TABLE ... CLUSTER BY&lt;/code&gt;, let automatic clustering settle over a day or two, then re-measure both the query and the credits in &lt;code&gt;AUTOMATIC_CLUSTERING_HISTORY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compare savings against the reclustering bill.&lt;/strong&gt; This is the step people skip. If the query got 20x faster and reclustering costs a few credits a day, keep it. If reclustering is burning more than the warehouse time you saved, suspend it with &lt;code&gt;ALTER TABLE ... SUSPEND RECLUSTER&lt;/code&gt; or drop the key.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The rollback is clean: &lt;code&gt;ALTER TABLE events DROP CLUSTERING KEY&lt;/code&gt; stops the service and leaves the data in place. Nothing breaks, you just stop paying for ordering. Before you reach for a clustering key at all, make sure the warehouse running the query is the right size, because the two levers interact. The &lt;a href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/&quot;&gt;warehouse sizing guide&lt;/a&gt; covers that side, and the rest of the &lt;a href=&quot;https://data-today.net/snowflake/&quot;&gt;Snowflake guides&lt;/a&gt; go deeper on the query profile.&lt;/p&gt;
&lt;h2 id=&quot;the-number-to-watch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-performance-clustering/#the-number-to-watch&quot;&gt;&lt;span&gt;The number to watch&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Track partitions scanned divided by partitions total for your heaviest recurring query. That ratio, not raw runtime, tells you whether pruning is working. When it is high on a big table you filter the same way every day, a clustering key is worth a test. When it is already low, leave the table alone and spend the credits somewhere they move the needle.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-performance-clustering/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-clustering-micropartitions&quot;&gt;Snowflake Documentation: Micro-partitions and data clustering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-auto-reclustering&quot;&gt;Snowflake Documentation: Automatic clustering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/functions/system_clustering_information&quot;&gt;Snowflake Documentation: SYSTEM$CLUSTERING_INFORMATION&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake Openflow: managed ingestion built on Apache NiFi</title>
    <link href="https://data-today.net/snowflake/snowflake-openflow/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-openflow/</id>
    <content type="html">&lt;p&gt;Every data team has the same unglamorous problem: getting data in. Change-data-capture from a transactional database, events off a Kafka topic, PDFs from SharePoint, rows from a SaaS API. The usual answer is a patchwork of Fivetran connectors, custom scripts, and a NiFi cluster someone has to babysit. &lt;strong&gt;Openflow&lt;/strong&gt; is Snowflake&#39;s bid to own that whole layer: a fully managed integration service, built on Apache NiFi, that moves structured and unstructured data from hundreds of sources into Snowflake with the platform&#39;s security and governance baked in. It went generally available across AWS, Azure, and GCP, and the pitch is that ingestion becomes a Snowflake feature instead of a separate system to run.&lt;/p&gt;
&lt;p&gt;This guide is for the data engineer who owns the pipelines and is tired of gluing ingestion tools together. What Openflow actually is, the two ways it runs, what it is good at, and the trade-off you are signing up for when you let Snowflake manage the pipe.&lt;/p&gt;
&lt;h2 id=&quot;what-is-openflow-and-why-build-it-on-nifi&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-openflow/#what-is-openflow-and-why-build-it-on-nifi&quot;&gt;&lt;span&gt;What is Openflow, and why build it on NiFi?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Apache NiFi is a battle-tested open-source dataflow tool: you build pipelines on a visual canvas out of &lt;strong&gt;processors&lt;/strong&gt;, small building blocks that read, transform, route, and write data, wired together with connections that buffer and backpressure. It has been the quiet workhorse of enterprise data movement for a decade. Openflow takes that engine, runs it as a managed service, and wires it natively into Snowflake&#39;s security model so you are not hand-rolling credentials and network rules.&lt;/p&gt;
&lt;p&gt;The headline capability is breadth. Openflow handles &lt;strong&gt;structured and unstructured data, in both batch and streaming modes&lt;/strong&gt;, through hundreds of processors. That unstructured part is the strategically interesting bit: it can pull documents off Google Drive, Box, or SharePoint and land them in Snowflake ready for Cortex to index, which is exactly the feedstock a &lt;a href=&quot;https://data-today.net/snowflake/snowflake-cortex-search/&quot;&gt;Cortex Search&lt;/a&gt; service or a RAG chatbot needs. The common use cases the docs call out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Database CDC.&lt;/strong&gt; Replicate change-data-capture from operational tables into Snowflake for centralized reporting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Streaming events.&lt;/strong&gt; Ingest real-time events from Apache Kafka for near real-time analytics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SaaS connectors.&lt;/strong&gt; Pull from platforms like LinkedIn Ads into Snowflake for reporting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unstructured for AI.&lt;/strong&gt; Continuously ingest documents from Drive, Box, and SharePoint so you can chat with them through Cortex.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You build a flow by dropping Snowflake and NiFi processors and controller services onto the Openflow canvas, the same mental model as NiFi, with Snowflake handling the runtime underneath.&lt;/p&gt;
&lt;h2 id=&quot;where-does-openflow-actually-run&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-openflow/#where-does-openflow-actually-run&quot;&gt;&lt;span&gt;Where does Openflow actually run?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the decision that shapes cost, security, and operational burden, because Openflow ships in two deployment types and they are genuinely different products under one name.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-openflow-fig.png&quot; alt=&quot;Bar chart of operational control by deployment type: about 40 for Snowflake SPCS deployment, 100 for Bring Your Own Cloud&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: BYOC keeps the data plane in your own VPC for maximum control, while the SPCS deployment trades that for managed simplicity. Source: Snowflake Openflow deployment documentation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Snowflake deployment (SPCS)&lt;/th&gt;
&lt;th&gt;Bring Your Own Cloud (BYOC)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where the data plane runs&lt;/td&gt;
&lt;td&gt;Inside Snowflake on Snowpark Container Services&lt;/td&gt;
&lt;td&gt;In your own cloud VPC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup and ops&lt;/td&gt;
&lt;td&gt;Simplest, self-contained in Snowflake&lt;/td&gt;
&lt;td&gt;You run the data plane, Snowflake runs the control plane&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Billing&lt;/td&gt;
&lt;td&gt;Compute-pool utilization, by uptime and usage&lt;/td&gt;
&lt;td&gt;Your cloud compute, infrastructure, and storage charges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Teams that want least operational overhead&lt;/td&gt;
&lt;td&gt;Sensitive data that must be preprocessed inside your own perimeter&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The split maps to a familiar trade-off. The &lt;strong&gt;SPCS deployment&lt;/strong&gt; runs entirely inside Snowflake on a compute pool, so it is the easy button: native security, no infrastructure of your own, billed on the compute pool&#39;s uptime. &lt;strong&gt;BYOC&lt;/strong&gt; runs the data-processing engine inside your own VPC while Snowflake manages the control plane, which is what you reach for when sensitive data has to be handled within your own cloud boundary before it ever moves. In both, the control plane that hosts the canvas and APIs is Snowflake-managed; only the data plane location changes.&lt;/p&gt;
&lt;p&gt;Authentication is one place Openflow genuinely simplifies life. The default is the &lt;strong&gt;Snowflake Managed Token&lt;/strong&gt;, short-lived credentials that Snowflake rotates for you, so you stop generating, storing, and rotating long-lived key pairs:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Openflow needs an account admin to grant the privileges that let a&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- role create deployments and runtimes. Fine-grained RBAC governs the rest.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; OPENFLOW &lt;span class=&quot;token keyword&quot;&gt;DATA&lt;/span&gt; PLANE INTEGRATION &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; ACCOUNT &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE openflow_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a BYOC deployment the runtime uses workload identity federation, exchanging its cloud identity such as an AWS IAM role for a Snowflake token, so there are still no long-lived secrets to leak.&lt;/p&gt;
&lt;h2 id=&quot;what-does-it-cost-and-what-should-you-watch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-openflow/#what-does-it-cost-and-what-should-you-watch&quot;&gt;&lt;span&gt;What does it cost, and what should you watch?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Openflow does not have a single price tag; it inherits the cost shape of wherever it runs. A &lt;strong&gt;SPCS deployment bills on compute-pool utilization&lt;/strong&gt;, meaning the uptime and compute usage of the container pool hosting your runtimes, the same serverless-ish model as anything on Snowpark Container Services. A BYOC deployment bills you directly through your cloud provider for the compute, infrastructure, and storage the data plane consumes, plus whatever Snowflake charges for the managed control plane.&lt;/p&gt;
&lt;p&gt;The practical watch items:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Runtimes are where flows execute, and you will have several.&lt;/strong&gt; Teams typically run multiple runtimes to isolate projects or environments, and each one is compute that costs while it is up. Idle runtimes are idle spend.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Streaming means always-on.&lt;/strong&gt; A continuous Kafka or CDC flow keeps a runtime warm around the clock, which is a very different cost profile from a nightly batch. Size that into your estimate before you commit a real-time pipeline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unstructured ingestion compounds downstream.&lt;/strong&gt; Landing documents is only step one; embedding and indexing them for Cortex is a second meter. Budget the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-cortex-search/&quot;&gt;Cortex Search&lt;/a&gt; cost alongside the ingestion cost, not after.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Openflow also brings real security plumbing: fine-grained RBAC, TLS in transit, PrivateLink compatibility, AWS Secrets Manager or HashiCorp Vault integration in BYOC, and Tri-Secret Secure support. That is the part that makes it credible for regulated data, and it is the reason to prefer it over a hand-built NiFi box you now have to secure and patch yourself.&lt;/p&gt;
&lt;h2 id=&quot;should-you-move-your-ingestion-onto-openflow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-openflow/#should-you-move-your-ingestion-onto-openflow&quot;&gt;&lt;span&gt;Should you move your ingestion onto Openflow?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Openflow makes the most sense when ingestion is already a real cost center: many sources, a mix of structured and unstructured data, and a NiFi or scripts setup that someone maintains by hand. Consolidating that onto a managed service inside your governance boundary is a genuine simplification, and the unstructured-to-Cortex path is something the bolt-on connectors do not do as cleanly. It is less compelling if you have one or two simple batch loads that &lt;code&gt;COPY INTO&lt;/code&gt; or &lt;a href=&quot;https://data-today.net/snowflake/snowflake-pipelines-streams-tasks/&quot;&gt;Snowpipe and Dynamic Tables&lt;/a&gt; already handle, where adding a NiFi-based service is more machinery than the job needs.&lt;/p&gt;
&lt;p&gt;The honest trade-off: Openflow is powerful and broad, but it is still NiFi underneath, which means a real flow-design skillset and runtimes you have to size and watch. It moves the babysitting from your own cluster to a managed service, it does not delete it. For a team drowning in connectors and custom CDC scripts, that is a clear win. For a team with a tidy handful of loads, it is a solution looking for a problem.&lt;/p&gt;
&lt;h2 id=&quot;the-honest-read&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-openflow/#the-honest-read&quot;&gt;&lt;span&gt;The honest read&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Openflow is Snowflake pulling the ingestion layer inside its walls, and for enterprises with sprawling, multi-format data movement that is a strong offer: one managed, governed, NiFi-powered service from any source to Snowflake, with a clean path for the unstructured data that feeds AI. &lt;strong&gt;The decision that actually matters is SPCS versus BYOC&lt;/strong&gt;, because that one choice sets your cost model, your security perimeter, and how much you operate yourself. Pick SPCS for least overhead, BYOC for data that must stay in your own cloud, and size your runtimes honestly, especially for streaming. Done right, ingestion stops being a patchwork and becomes a feature. Done lazily, it is just NiFi with a bigger invoice.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-openflow/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/data-integration/openflow/about&quot;&gt;Snowflake Documentation: About Openflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/data-integration/openflow/cost-spcs&quot;&gt;Snowflake Documentation: Openflow Snowflake Deployment cost and scaling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/data-integration/openflow/cost-byoc&quot;&gt;Snowflake Documentation: Openflow BYOC cost and scaling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nifi.apache.org/&quot;&gt;Apache NiFi: Project documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Should you put your data lake in Snowflake Iceberg tables?</title>
    <link href="https://data-today.net/snowflake/snowflake-iceberg-tables/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-iceberg-tables/</id>
    <content type="html">&lt;p&gt;The question landing in every enterprise data architecture review right now: do we keep paying Snowflake to store our data, or do we put it in open &lt;strong&gt;Apache Iceberg&lt;/strong&gt; tables and keep one copy that every engine can read? Iceberg is an open table format that adds database features, ACID transactions, schema evolution, hidden partitioning, and time-travel snapshots, on top of plain Parquet files sitting in your own S3, GCS, or Azure storage. Snowflake supports it natively. The headline that makes finance lean in: with an external volume, &lt;strong&gt;Iceberg tables incur zero Snowflake storage cost&lt;/strong&gt;, because your cloud provider bills you for the bytes directly. The headline that should make architects slow down: not all Iceberg tables are equal, and the catalog you choose decides how much of Snowflake you actually get to keep.&lt;/p&gt;
&lt;p&gt;This guide is for the data engineer or platform lead weighing a lakehouse move on Snowflake: when Iceberg is the right call, what you give up, and how to avoid the interoperability promise quietly costing you more than it saves.&lt;/p&gt;
&lt;h2 id=&quot;what-problem-does-iceberg-actually-solve&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-tables/#what-problem-does-iceberg-actually-solve&quot;&gt;&lt;span&gt;What problem does Iceberg actually solve?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A standard Snowflake table stores data in Snowflake&#39;s proprietary format. It is fast and fully managed, but the data is locked behind Snowflake&#39;s engine: Spark, Trino, or Databricks cannot read it without exporting a copy. The moment two teams want two engines on the same data, you are either copying it or paying twice.&lt;/p&gt;
&lt;p&gt;Iceberg breaks that lock. The table data lives as Parquet in open cloud storage, and an &lt;strong&gt;Iceberg catalog&lt;/strong&gt; tracks which files make up the current table state. Any Iceberg-aware engine can read it. So the real question is not &amp;quot;Snowflake or open format&amp;quot; but &lt;strong&gt;who owns the catalog&lt;/strong&gt;, because Snowflake supports two very different models and they are not interchangeable.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Snowflake as the catalog (Snowflake-managed):&lt;/strong&gt; Snowflake owns the metadata pointer, handles maintenance like compaction, and gives you read and write with full platform support. The data still sits in your external volume, so storage stays cheap, but Snowflake behaves almost like it is a native table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;External catalog (AWS Glue, Databricks Unity Catalog, a remote Iceberg REST catalog):&lt;/strong&gt; another system owns the metadata. Snowflake connects through a catalog integration and gives you &lt;strong&gt;limited platform support&lt;/strong&gt;. Snowflake does not manage the table lifecycle here.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-much-of-snowflake-do-you-give-up-with-an-external-catalog&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-tables/#how-much-of-snowflake-do-you-give-up-with-an-external-catalog&quot;&gt;&lt;span&gt;How much of Snowflake do you give up with an external catalog?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the trade-off the marketing glosses over, and it is the single most important thing to get right. Going Snowflake-managed keeps nearly the whole platform. Going external-catalog trades platform features for ecosystem neutrality.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-iceberg-tables-fig.png&quot; alt=&quot;Bar chart of Snowflake platform features supported: about 9 for a Snowflake-managed catalog versus 3 for an external catalog&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: a Snowflake-managed Iceberg catalog retains most platform features while an external catalog supports a much smaller subset. Source: Snowflake Iceberg tables documentation, considerations and limitations.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Per Snowflake&#39;s own documentation, here is what the catalog choice actually costs you:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Snowflake-managed catalog&lt;/th&gt;
&lt;th&gt;External catalog&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read and write&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;Full (writes supported via Iceberg REST)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clustering keys&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replication&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloning&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Not supported (externally managed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard streams (CDC)&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Insert-only streams only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lifecycle maintenance (compaction)&lt;/td&gt;
&lt;td&gt;Snowflake handles it&lt;/td&gt;
&lt;td&gt;You own it in the external engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query from other engines&lt;/td&gt;
&lt;td&gt;Sync to Snowflake Open Catalog&lt;/td&gt;
&lt;td&gt;Native, that is the point&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The pattern that follows: if Snowflake is your primary engine and you just want cheap open storage, use &lt;strong&gt;Snowflake as the catalog&lt;/strong&gt; and sync to Open Catalog when another engine needs read access. If a Spark or Databricks platform is the system of record and Snowflake is a guest, use the external catalog and accept that clustering, cloning, and replication are off the table. Snowflake even supports a catalog-linked database that stays in sync with a remote Iceberg REST catalog, including bidirectional access to Databricks Unity Catalog, so the two platforms can share one copy of the data.&lt;/p&gt;
&lt;h2 id=&quot;what-does-it-really-cost-and-where-does-the-bill-hide&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-tables/#what-does-it-really-cost-and-where-does-the-bill-hide&quot;&gt;&lt;span&gt;What does it really cost, and where does the bill hide?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The storage saving is real but narrower than it sounds. Snowflake bills you for &lt;strong&gt;virtual warehouse compute and cloud services&lt;/strong&gt; whenever you query or maintain Iceberg tables, exactly as it does for native tables. What changes is storage.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-iceberg-tables-fig2.png&quot; alt=&quot;Bar chart of Snowflake storage bill: 100 for a standard table, 0 for Iceberg on an external volume, 100 for Iceberg on Snowflake-managed storage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: with an external volume, Snowflake charges no storage for Iceberg, your cloud provider bills you instead; with Snowflake-managed storage, Snowflake charges storage as normal. Source: Snowflake Iceberg tables billing documentation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The nuance that catches teams out: &lt;strong&gt;storage is free from Snowflake only when you use your own external volume.&lt;/strong&gt; If you pick the convenience option of &lt;code&gt;EXTERNAL_VOLUME = SNOWFLAKE_MANAGED&lt;/code&gt; storage, Snowflake charges for storage just like a normal table, and the headline saving evaporates. And the most common surprise bill is geography. If your Snowflake account and your external volume sit in different regions, every query triggers &lt;strong&gt;cross-region egress that your cloud provider charges you for&lt;/strong&gt;, and Snowflake adds cross-region data-transfer usage on top for managed tables. Keep compute and storage in the same region or that interoperability dream turns into an egress line item.&lt;/p&gt;
&lt;p&gt;Two more honest caveats before you migrate a critical table:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No Fail-safe.&lt;/strong&gt; Iceberg tables on an external volume get no Snowflake Fail-safe recovery. You own data protection and recovery for that storage. For a standard table, Snowflake&#39;s seven-day Fail-safe is a safety net you are quietly giving up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintenance is real work.&lt;/strong&gt; For externally managed tables, you own compaction and cleanup. Excessive position deletes can actually block table creation and refresh, and orphan files from failed writes can make your storage bill drift above what Snowflake reports. This is operational overhead a native table never asked of you.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;when-is-iceberg-the-right-call-and-when-is-it-a-trap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-tables/#when-is-iceberg-the-right-call-and-when-is-it-a-trap&quot;&gt;&lt;span&gt;When is Iceberg the right call, and when is it a trap?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Reach for Iceberg when you have a genuine multi-engine reality or an existing data lake you cannot or will not move into Snowflake. The open format pays off precisely when more than one tool needs the same data and the alternative is copies that drift. Snowflake says it plainly: Iceberg tables are ideal for existing data lakes you choose not to store in Snowflake.&lt;/p&gt;
&lt;p&gt;Do not reach for Iceberg when Snowflake is your only engine and you just heard &amp;quot;open format&amp;quot; in a keynote. For a single-engine shop, a Snowflake-managed Iceberg table on an external volume buys you cheaper storage and an exit option, which is a reasonable hedge, but a standard table buys you Fail-safe, zero maintenance, and every feature with no asterisks. The worst outcome is adopting an external catalog for openness you never use, then discovering six months later that you cannot cluster your biggest table or replicate it for disaster recovery.&lt;/p&gt;
&lt;p&gt;If cost is the driver, weigh the storage saving against the maintenance time and egress risk before you commit, the same discipline from the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/&quot;&gt;warehouse sizing guide&lt;/a&gt;: measure the real number, do not assume the cheap-looking option is cheaper once you count everything. The rest of the &lt;a href=&quot;https://data-today.net/snowflake/&quot;&gt;Snowflake guides&lt;/a&gt; cover the compute side that Iceberg does not change.&lt;/p&gt;
&lt;h2 id=&quot;the-decision-in-one-line&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-tables/#the-decision-in-one-line&quot;&gt;&lt;span&gt;The decision in one line&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pick the catalog before you pick the format. Snowflake-managed Iceberg gives you open storage with almost the whole platform intact; an external catalog gives you true engine neutrality at the cost of clustering, cloning, replication, and a maintenance burden you now own. &lt;strong&gt;Choose external only when a second engine is genuinely the system of record&lt;/strong&gt;, otherwise you are paying in lost features for an openness you will never spend.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-tables/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg&quot;&gt;Snowflake Documentation: Apache Iceberg tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-internal-storage&quot;&gt;Snowflake Documentation: Snowflake storage for Apache Iceberg tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-catalog-linked-database&quot;&gt;Snowflake Documentation: Use a catalog-linked database for Apache Iceberg tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://iceberg.apache.org/spec/&quot;&gt;Apache Iceberg: Table specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake RBAC and masking: lock it down without grinding to a halt</title>
    <link href="https://data-today.net/snowflake/snowflake-governance-rbac/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-governance-rbac/</id>
    <content type="html">&lt;p&gt;Governance is where a fast-moving Snowflake account quietly turns into a liability. Someone needs access, an admin grants it straight to their user, and a year later nobody can answer who can see the salary table. The fix is not more process, it is using the access model Snowflake actually gives you. Snowflake is &lt;strong&gt;role-based&lt;/strong&gt;: privileges are granted to roles, and roles are granted to users, never privileges to users directly. Get the role design right and you collapse what would be &lt;strong&gt;roughly 10,000 individual grants down to a few hundred&lt;/strong&gt; while making access auditable instead of archaeological.&lt;/p&gt;
&lt;p&gt;This guide is for the data engineer or platform owner who has to keep Snowflake both usable and defensible: analysts unblocked, auditors satisfied, and PII not leaking into a dashboard. We will stick to how Snowflake&#39;s RBAC and masking actually behave.&lt;/p&gt;
&lt;h2 id=&quot;why-grant-to-roles-and-not-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/#why-grant-to-roles-and-not-users&quot;&gt;&lt;span&gt;Why grant to roles and not users?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In Snowflake, a privilege (say, &lt;code&gt;SELECT&lt;/code&gt; on a schema) is granted to a &lt;strong&gt;role&lt;/strong&gt;, and a user gets access by being granted that role. Grant directly to users and the math explodes: fifty users who each need access to two hundred objects is up to ten thousand grants to create, track, and eventually revoke. Miss a few on offboarding and you have a standing audit finding.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-governance-rbac-fig.png&quot; alt=&quot;Bar chart of grants to manage: about 10,000 with direct user grants versus 260 with functional and access roles, log scale&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: a two-layer role hierarchy collapses grant sprawl from roughly 10,000 direct user grants to about 260. Source: Snowflake documentation on access control.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The pattern that scales is a &lt;strong&gt;two-layer role hierarchy&lt;/strong&gt;, which Snowflake&#39;s own guidance recommends. &lt;strong&gt;Access roles&lt;/strong&gt; own the privileges on objects: &lt;code&gt;analytics_db_read&lt;/code&gt; holds &lt;code&gt;SELECT&lt;/code&gt; on the analytics schemas, &lt;code&gt;raw_db_write&lt;/code&gt; holds write on the landing zone. &lt;strong&gt;Functional roles&lt;/strong&gt; map to jobs: &lt;code&gt;data_analyst&lt;/code&gt;, &lt;code&gt;data_engineer&lt;/code&gt;, &lt;code&gt;bi_developer&lt;/code&gt;. You grant access roles to functional roles, and functional roles to people. Now a new analyst gets exactly one grant, &lt;code&gt;data_analyst&lt;/code&gt;, and inherits everything that role is supposed to see.&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Access role owns the object privileges.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; ROLE analytics_read&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;USAGE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DATABASE&lt;/span&gt; analytics &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE analytics_read&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;USAGE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SCHEMA&lt;/span&gt; analytics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;marts &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE analytics_read&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ALL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLES&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SCHEMA&lt;/span&gt; analytics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;marts &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE analytics_read&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- Functional role = the job. It inherits the access role.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; ROLE data_analyst&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; ROLE analytics_read &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE data_analyst&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- People get one grant: the job.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; ROLE data_analyst &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;USER&lt;/span&gt; jdoe&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two discipline points keep this clean. Keep &lt;code&gt;ACCOUNTADMIN&lt;/code&gt; for break-glass only and run day-to-day administration through &lt;code&gt;SECURITYADMIN&lt;/code&gt; and &lt;code&gt;SYSADMIN&lt;/code&gt;, because handing out the top role defeats the whole hierarchy. And give every object a deliberate owner role, so &lt;code&gt;OWNERSHIP&lt;/code&gt; is not scattered across whoever happened to run the &lt;code&gt;CREATE&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-protect-specific-columns-without-copying-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/#how-do-i-protect-specific-columns-without-copying-data&quot;&gt;&lt;span&gt;How do I protect specific columns without copying data?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;RBAC controls which tables a role can touch. It does not, on its own, hide the &lt;code&gt;ssn&lt;/code&gt; column from an analyst who legitimately needs the rest of the row. That is what &lt;strong&gt;Dynamic Data Masking&lt;/strong&gt; is for, and it is the governance feature that earns its keep fastest.&lt;/p&gt;
&lt;p&gt;A masking policy is a schema-level object that rewrites a column&#39;s value at query time based on the querying role. The data on disk never changes; what a user sees is decided per query.&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; MASKING POLICY mask_email &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; string &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;CASE&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;WHEN&lt;/span&gt; CURRENT_ROLE&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;PII_READER&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;SECURITYADMIN&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt; val
        &lt;span class=&quot;token keyword&quot;&gt;ELSE&lt;/span&gt; REGEXP_REPLACE&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.+@&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;****@&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; customers &lt;span class=&quot;token keyword&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;COLUMN&lt;/span&gt; email &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; MASKING POLICY mask_email&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now &lt;code&gt;PII_READER&lt;/code&gt; sees real email addresses and everyone else sees &lt;code&gt;****@example.com&lt;/code&gt;, from the same table, with no copy and no second pipeline. The leverage Snowflake&#39;s docs call out: you &lt;strong&gt;write the policy once and apply it to thousands of columns&lt;/strong&gt;, and you can change the policy&#39;s logic centrally without reapplying it anywhere. Pair it with &lt;strong&gt;tag-based masking&lt;/strong&gt;, attach the policy to a &lt;code&gt;pii_email&lt;/code&gt; tag and tag the columns, and protection follows the data automatically as new tables appear. Row-level filtering has a sibling feature, &lt;strong&gt;row access policies&lt;/strong&gt;, which hides whole rows by role using the same query-time model.&lt;/p&gt;
&lt;p&gt;A few realities to plan around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Data Masking is an Enterprise Edition feature.&lt;/strong&gt; If you are on Standard, it is not available, and that may itself be the reason to upgrade.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A column takes one masking policy at a time.&lt;/strong&gt; You cannot stack two; decide the policy per column.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Masking interacts with materialized views.&lt;/strong&gt; Apply policies to the base table columns, not to a materialized view, or you will hit errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Where masking gets genuinely powerful is in combination with tags. Define the sensitivity taxonomy once, &lt;code&gt;pii&lt;/code&gt;, &lt;code&gt;financial&lt;/code&gt;, &lt;code&gt;restricted&lt;/code&gt;, attach a masking policy to each tag, and then governance becomes a tagging exercise rather than a per-column chase. Snowflake can also help you find what to tag: &lt;strong&gt;sensitive data classification&lt;/strong&gt; scans columns and proposes semantic categories like email or phone number, so you are not auditing thousands of columns by eye. The pattern that scales is classify, tag, mask-by-tag, because new tables that inherit a tagged column&#39;s lineage pick up protection automatically instead of waiting for someone to remember.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-roll-this-out-on-an-account-that-is-already-messy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/#how-do-i-roll-this-out-on-an-account-that-is-already-messy&quot;&gt;&lt;span&gt;How do I roll this out on an account that is already messy?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You rarely get a greenfield account. Retrofit in order, and audit as you go.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;See what exists.&lt;/strong&gt; &lt;code&gt;SHOW GRANTS&lt;/code&gt; and the &lt;code&gt;ACCOUNT_USAGE.GRANTS_TO_USERS&lt;/code&gt; view expose every direct-to-user grant. That list is your cleanup backlog and, usually, a sobering one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stand up the hierarchy alongside the mess.&lt;/strong&gt; Create the access and functional roles, grant the access roles into them, and move users onto functional roles one team at a time. Nothing breaks for users still on the old grants while you migrate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Revoke the direct grants last.&lt;/strong&gt; Once a team is fully on functional roles, strip their direct-to-user grants. Now access is described entirely by which roles a person holds, which is exactly what an auditor wants to see.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Classify and mask the sensitive columns.&lt;/strong&gt; Tag PII columns, attach masking policies through the tags, and verify with the &lt;code&gt;POLICY_REFERENCES&lt;/code&gt; view that every sensitive column is actually covered.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Audit continuously, not at year-end: &lt;code&gt;ACCOUNT_USAGE.POLICY_REFERENCES&lt;/code&gt; lists every object a masking policy is set on, and the &lt;code&gt;GRANTS_TO_ROLES&lt;/code&gt; view lets you answer &amp;quot;who can read this table&amp;quot; with a query instead of a meeting. The same instinct from the rest of the &lt;a href=&quot;https://data-today.net/snowflake/&quot;&gt;Snowflake guides&lt;/a&gt; applies, measure the real state in &lt;code&gt;ACCOUNT_USAGE&lt;/code&gt; rather than trusting the diagram on the wiki.&lt;/p&gt;
&lt;h2 id=&quot;the-test-that-proves-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/#the-test-that-proves-it-works&quot;&gt;&lt;span&gt;The test that proves it works&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pick your most sensitive table and ask: can you answer &amp;quot;who can see this column, and what do they see&amp;quot; with a single query? If yes, your RBAC and masking are doing their job. If it takes a meeting and three Slack threads, the access model is living in people&#39;s heads instead of in Snowflake, and that gap is exactly what fails an audit.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/security-access-control-overview&quot;&gt;Snowflake Documentation: Overview of Access Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/security-column-ddm-intro&quot;&gt;Snowflake Documentation: Understanding Dynamic Data Masking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tag-based-masking-policies&quot;&gt;Snowflake Documentation: Tag-based masking policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/security-row-intro&quot;&gt;Snowflake Documentation: Row access policies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake Gen2 warehouses: faster compute you have to opt into</title>
    <link href="https://data-today.net/snowflake/snowflake-gen2-warehouses/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-gen2-warehouses/</id>
    <content type="html">&lt;p&gt;Snowflake quietly shipped a second generation of its compute engine, and most teams have not noticed they are now paying for the choice. &lt;strong&gt;Generation 2 standard warehouses (Gen2)&lt;/strong&gt; run on faster underlying hardware with software optimizations to delete, update, merge, and table-scan operations, and Snowflake says the majority of queries finish faster as a result. That sounds like a free win, but it is not free: Gen2 bills at a higher credit rate than Gen1, and depending on when and where your account was created, you may have to ask for it explicitly with a SQL clause. The question that decides whether Gen2 helps or hurts your bill: does the speedup beat the rate increase for your workload?&lt;/p&gt;
&lt;p&gt;This guide is for the data engineer or FinOps owner who runs the warehouses and signs off on the credit spend. If you have a heavy data-engineering pipeline or a wall of analytics queries, Gen2 is the single most consequential warehouse setting you are probably not thinking about.&lt;/p&gt;
&lt;h2 id=&quot;what-actually-changed-under-the-hood&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/#what-actually-changed-under-the-hood&quot;&gt;&lt;span&gt;What actually changed under the hood?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A Snowflake virtual warehouse is just a cluster of compute that runs your queries, sized from XS up to 6XL, and you pay credits per second it runs. Gen1, the original engine, is what every account has used for years. Gen2 keeps the same sizes and the same per-second model but swaps in faster hardware and engine improvements aimed squarely at the operations that dominate modern pipelines: the DML that rewrites tables and the scans that feed big aggregations.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-gen2-warehouses-fig.png&quot; alt=&quot;Bar chart of illustrative query runtime: 100 for Gen1 standard versus about 65 for Gen2 standard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: Gen2 aims to finish the same query faster, the exact gain depends on your workload, so benchmark it. Source: Snowflake Gen2 warehouse documentation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Snowflake is careful, and you should be too: the exact gain depends on your configuration and workload, and the docs explicitly tell you to test it rather than assume. &lt;strong&gt;Gen2 is not available for the two largest sizes, X5LARGE and X6LARGE&lt;/strong&gt;, and it applies only to standard warehouses, not Snowpark-optimized ones. There is one genuine bonus that ships with it: a new Gen2 warehouse turns on the Query Acceleration Service by default with a scale factor of 2, which lets bursty queries borrow extra serverless compute for the heavy parts.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-actually-get-a-gen2-warehouse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/#how-do-you-actually-get-a-gen2-warehouse&quot;&gt;&lt;span&gt;How do you actually get a Gen2 warehouse?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where teams trip, because the default depends on your account&#39;s age and region. For new organizations created after the mid-2025 rollout dates in supported regions, &lt;strong&gt;standard warehouses now default to Gen2&lt;/strong&gt;. For everyone else, if you do not specify a generation when you create a warehouse, you still get Gen1. So an older account is almost certainly running Gen1 everywhere and paying Gen1 speeds without realizing there is a switch.&lt;/p&gt;
&lt;p&gt;The switch is one clause. The recommended syntax is the &lt;code&gt;GENERATION&lt;/code&gt; parameter on &lt;code&gt;CREATE WAREHOUSE&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Create a new Gen2 standard warehouse. Without this clause an&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- older account silently gets Gen1.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; WAREHOUSE etl_wh
  GENERATION &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;2&#39;&lt;/span&gt;
  WAREHOUSE_SIZE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MEDIUM&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can flip an existing warehouse in place, running or suspended, with a single &lt;code&gt;ALTER&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Convert an existing warehouse to Gen2 without recreating it.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE etl_wh &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; GENERATION &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One billing gotcha worth knowing before you convert a live warehouse: if you convert it while queries are running, the in-flight queries finish on Gen1 compute while new queries start on Gen2, and &lt;strong&gt;you are billed for both sets of compute&lt;/strong&gt; until the old queries drain. Convert while suspended to avoid the double charge, or convert while running if you care more about zero downtime than a few minutes of overlap. Note also that the &lt;code&gt;GENERATION&lt;/code&gt; clause is not in Snowsight yet, so this is a SQL-only change today, and the setting shows up in the &lt;code&gt;resource_constraint&lt;/code&gt; column of &lt;code&gt;SHOW WAREHOUSES&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Confirm which generation each warehouse is running.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SHOW&lt;/span&gt; WAREHOUSES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- look at the &quot;resource_constraint&quot; column: STANDARD_GEN_2 means Gen2.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;does-gen2-actually-save-you-money&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/#does-gen2-actually-save-you-money&quot;&gt;&lt;span&gt;Does Gen2 actually save you money?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the only question that matters, and the honest answer is: it depends, so measure. Gen2 finishes faster, which means fewer credit-seconds per query, but it charges a &lt;strong&gt;higher credit rate per second&lt;/strong&gt; than Gen1, with the exact rates published in Snowflake&#39;s Service Consumption Table. The maths is a race between two effects.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Pushes cost down&lt;/th&gt;
&lt;th&gt;Pushes cost up&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Query runtime&lt;/td&gt;
&lt;td&gt;Faster, so fewer seconds billed&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credit rate&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Higher per-second rate than Gen1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency&lt;/td&gt;
&lt;td&gt;More queries done per running hour&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-suspend gaps&lt;/td&gt;
&lt;td&gt;Shorter active windows&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The break-even logic is simple. If Gen2 cuts your runtime by more than the rate premium, you win. A warehouse running heavy merges and large scans, exactly what Gen2 was tuned for, is the most likely winner. A warehouse running tiny, cheap queries where the bottleneck is not compute may see the rate increase swamp a speedup it barely benefits from. The right move is to A/B it: run a representative workload on a Gen1 and a Gen2 copy, then compare credits in &lt;code&gt;ACCOUNT_USAGE&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Compare credits burned per warehouse over the last 7 days.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;credits_used&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; credits
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt;   snowflake&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account_usage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;warehouse_metering_history
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt;  start_time &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; DATEADD&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;day&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; warehouse_name
&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; credits &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pair that with &lt;code&gt;QUERY_HISTORY&lt;/code&gt; to confirm the runtime actually dropped, not just the credit line. The discipline here is the same one from the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/&quot;&gt;warehouse sizing guide&lt;/a&gt;: never assume the faster-or-newer option is cheaper until you have the two numbers side by side.&lt;/p&gt;
&lt;h2 id=&quot;what-should-you-do-this-week&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/#what-should-you-do-this-week&quot;&gt;&lt;span&gt;What should you do this week?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you run an older account, you are almost certainly on Gen1 everywhere and leaving a possible speedup on the table, so this is worth ten minutes. The plan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Find your heaviest warehouse.&lt;/strong&gt; The one with the most credits in the query above, usually an ETL or transformation warehouse doing merges and big scans, is the best Gen2 candidate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clone the workload, not the prod warehouse.&lt;/strong&gt; Point a representative job at a &lt;code&gt;GENERATION = &#39;2&#39;&lt;/code&gt; copy and a Gen1 copy, same size, and compare credits and runtime over a real day.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mind replication.&lt;/strong&gt; If you replicate warehouses across regions, every secondary region must also support Gen2, or a Gen2 warehouse may fail to resume after a failover. Test the failover path before you standardize on Gen2.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leave tiny, idle warehouses alone.&lt;/strong&gt; A warehouse that mostly serves cheap dashboard queries will feel the rate increase more than the speedup. Gen2 earns its premium on heavy work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the read on Gen2 against the rest of your compute strategy, the other &lt;a href=&quot;https://data-today.net/snowflake/&quot;&gt;Snowflake guides&lt;/a&gt; cover sizing, clustering, and the pipeline patterns that decide how much work a warehouse does in the first place.&lt;/p&gt;
&lt;h2 id=&quot;the-honest-read&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/#the-honest-read&quot;&gt;&lt;span&gt;The honest read&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Gen2 is a real upgrade, not marketing: faster hardware, smarter DML, Query Acceleration on by default. But Snowflake made it an opt-in with a higher rate, which means it is a FinOps decision dressed as a performance feature. &lt;strong&gt;The teams that win are the ones that benchmark before they standardize&lt;/strong&gt;, because for compute-heavy pipelines Gen2 can pay for its premium several times over, and for light, bursty workloads it can quietly raise the bill for a speedup you never needed. Run the two-warehouse test, read the two numbers, then decide. Do not let a default, old or new, make the call for you.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-gen2&quot;&gt;Snowflake Documentation: Snowflake generation 2 standard warehouses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/cost-understanding-compute&quot;&gt;Snowflake Documentation: Virtual warehouse credit usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/query-acceleration-service&quot;&gt;Snowflake Documentation: Using the Query Acceleration Service&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Cortex Search: the managed RAG engine inside Snowflake</title>
    <link href="https://data-today.net/snowflake/snowflake-cortex-search/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-cortex-search/</id>
    <content type="html">&lt;p&gt;Every team building a chatbot on their own data hits the same wall: retrieval. The large language model is the easy part; the hard part is finding the right three paragraphs out of a million to feed it, keeping that index fresh as the data changes, and not standing up a separate vector database to do it. &lt;strong&gt;Cortex Search&lt;/strong&gt; is Snowflake&#39;s answer: a fully managed hybrid search service that embeds your text, runs vector and keyword search together with semantic reranking, and refreshes the index automatically, all inside Snowflake. It is the retrieval engine behind enterprise RAG chatbots and high-quality search bars, and it pairs directly with the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-cortex-agents/&quot;&gt;Cortex Agents&lt;/a&gt; framework as the tool that answers questions about unstructured data. The thing to understand before you ship it: it is genuinely low-effort to stand up, but the bill has several meters, and one of them runs even when nobody is searching.&lt;/p&gt;
&lt;p&gt;This guide is for the engineer asked to &amp;quot;add search&amp;quot; or &amp;quot;build a chatbot on our docs&amp;quot; who needs to know what Cortex Search does, how good it is out of the box, and where the cost hides.&lt;/p&gt;
&lt;h2 id=&quot;why-not-just-use-a-vector-database&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-search/#why-not-just-use-a-vector-database&quot;&gt;&lt;span&gt;Why not just use a vector database?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The default 2024-era answer to RAG was: chunk your text, run it through an embedding model, load the vectors into a dedicated vector store, and query it. That works, but it is a second system to run, secure, and keep in sync with the source data, and tuning retrieval quality is a research project of its own. Cortex Search collapses that stack. You point it at a column of text in a Snowflake table, and it handles embedding, indexing, refresh, and serving.&lt;/p&gt;
&lt;p&gt;The quality story is the part that earns the &amp;quot;managed&amp;quot; label. Cortex Search does not just do vector similarity; it takes a &lt;strong&gt;hybrid approach combining vector search, keyword search, and a semantic reranking step&lt;/strong&gt;, which is what gets you good results across messy real-world queries without hand-tuning. Vector search catches &amp;quot;internet is down&amp;quot; matching &amp;quot;connectivity problem&amp;quot;; keyword search catches exact product codes and names that embeddings blur; reranking puts the genuinely relevant hits on top. You get all three with no parameters to fiddle.&lt;/p&gt;
&lt;p&gt;Creating a service is one SQL statement:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Point Cortex Search at a text column. It embeds, indexes,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- and keeps the result fresh on its own.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; CORTEX SEARCH SERVICE transcript_search_service
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; transcript_text
  ATTRIBUTES region
  WAREHOUSE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cortex_search_wh
  TARGET_LAG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;1 day&#39;&lt;/span&gt;
  EMBEDDING_MODEL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;snowflake-arctic-embed-l-v2.0&#39;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; transcript_text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; agent_id
    &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; support_transcripts
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That &lt;code&gt;TARGET_LAG = &#39;1 day&#39;&lt;/code&gt; is the freshness contract: the service checks the base table for changes about once a day and re-embeds only what changed. The embedding model is swappable, from the fast English-only &lt;code&gt;snowflake-arctic-embed-m-v1.5&lt;/code&gt; default up to multilingual and long-context options.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-query-it-and-how-do-you-chunk-the-text&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-search/#how-do-you-query-it-and-how-do-you-chunk-the-text&quot;&gt;&lt;span&gt;How do you query it, and how do you chunk the text?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Querying is a REST API, a Python API, or a SQL preview function. The SQL preview is the fastest way to sanity-check that retrieval works before you wire up an app:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Preview retrieval straight from a worksheet, with a filter on an attribute.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; PARSE_JSON&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  SNOWFLAKE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CORTEX&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SEARCH_PREVIEW&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;cortex_search_db.services.transcript_search_service&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;{
       &quot;query&quot;: &quot;internet issues&quot;,
       &quot;columns&quot;: [&quot;transcript_text&quot;, &quot;region&quot;],
       &quot;filter&quot;: {&quot;@eq&quot;: {&quot;region&quot;: &quot;North America&quot;}},
       &quot;limit&quot;: 1
     }&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;results&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; results&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The single biggest lever on quality you control is &lt;strong&gt;chunk size&lt;/strong&gt;. Cortex Search truncates anything longer than the embedding model&#39;s context window before vectorizing, and Snowflake&#39;s own research says smaller chunks retrieve more precisely. The recommendation is concrete: &lt;strong&gt;split your text into chunks of no more than 512 tokens&lt;/strong&gt;, roughly 385 English words. Snowflake gives you a built-in function so you do not have to write a splitter:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Chunk long documents before indexing for sharper retrieval.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; SNOWFLAKE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CORTEX&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SPLIT_TEXT_RECURSIVE_CHARACTER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  document_text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;markdown&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; chunks
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; raw_documents&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Granting access follows Snowflake&#39;s normal model, and it matters because search services run with &lt;strong&gt;owner&#39;s rights&lt;/strong&gt;: the service reads data as its creator, so you control exposure through who you grant usage to, not through the caller&#39;s row access. Lock that down deliberately, the same discipline as the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/&quot;&gt;RBAC and masking guide&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;USAGE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; CORTEX SEARCH SERVICE transcript_search_service &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE support_app&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-does-it-actually-cost&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-search/#what-does-it-actually-cost&quot;&gt;&lt;span&gt;What does it actually cost?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is where the managed convenience meets the invoice, and it is the part teams underestimate. A Cortex Search service bills on &lt;strong&gt;four separate meters&lt;/strong&gt;, not one.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-cortex-search-fig.png&quot; alt=&quot;Bar chart of illustrative Cortex Search cost share: embedding tokens 30 percent, serving compute 35 percent, warehouse refresh 20 percent, storage 15 percent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: serving compute, billed per GB of indexed data per month, runs even when no queries are served. Source: Snowflake Cortex Search cost documentation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Meter&lt;/th&gt;
&lt;th&gt;What it charges for&lt;/th&gt;
&lt;th&gt;The gotcha&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Embedding tokens&lt;/td&gt;
&lt;td&gt;Vectorizing each text row&lt;/td&gt;
&lt;td&gt;Only added or changed rows re-embed, so churn drives it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serving compute&lt;/td&gt;
&lt;td&gt;Per GB of indexed data per month&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Bills while the service is available, even with zero queries&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warehouse refresh&lt;/td&gt;
&lt;td&gt;Running the source query on refresh&lt;/td&gt;
&lt;td&gt;No credits if nothing changed since last refresh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;The materialized index and structures&lt;/td&gt;
&lt;td&gt;Flat rate per terabyte&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The one that surprises people is &lt;strong&gt;serving compute, charged per gigabyte of indexed data per month whether or not anyone searches&lt;/strong&gt;. A big index that sits idle still costs money, because the low-latency serving layer is kept warm for you. Snowflake added a fix worth knowing: you can set &lt;code&gt;AUTO_SUSPEND&lt;/code&gt; (minimum 30 minutes of inactivity) so an idle service parks its serving compute and resumes on the next query. The first query after a suspend waits for the resume and concurrent ones get a 429, so build retry logic into your client.&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Park serving compute after 30 minutes idle to stop paying for an unused index.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; CORTEX SEARCH SERVICE transcript_search_service &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; AUTO_SUSPEND &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Track the spend per service with the &lt;code&gt;CORTEX_SEARCH_DAILY_USAGE_HISTORY&lt;/code&gt; view, and right-size the refresh warehouse: Snowflake recommends a dedicated warehouse &lt;strong&gt;no larger than MEDIUM&lt;/strong&gt; for each service.&lt;/p&gt;
&lt;h2 id=&quot;what-are-the-limits-you-will-hit&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-search/#what-are-the-limits-you-will-hit&quot;&gt;&lt;span&gt;What are the limits you will hit?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Set expectations before you scale. A service&#39;s materialized result must be &lt;strong&gt;under 100 million rows&lt;/strong&gt; or the create fails, though you can ask Snowflake to raise it. A single service is rate-limited to &lt;strong&gt;20 queries per second&lt;/strong&gt; and 140 across the account by default, with 429s when you exceed it, again contact your account team to raise it. Because the source query must qualify for Dynamic Table incremental refresh, the same query restrictions apply, so an arbitrary complex join may not be eligible. And Cortex Search does not yet support cloning, and the tables it reads must not be dropped or modified while the service runs, so coordinate schema changes around it.&lt;/p&gt;
&lt;p&gt;None of these are dealbreakers for a typical knowledge base, but they are real edges, and hitting the row cap or the QPS limit in production without knowing it exists is an avoidable outage.&lt;/p&gt;
&lt;h2 id=&quot;the-honest-read&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-search/#the-honest-read&quot;&gt;&lt;span&gt;The honest read&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cortex Search is one of the cleaner managed-AI stories Snowflake tells: it deletes the vector-database tier, gives you genuinely good hybrid retrieval with no tuning, and keeps the index fresh on its own. For building RAG on data that already lives in Snowflake, it is the path of least resistance, and the tight integration with &lt;a href=&quot;https://data-today.net/snowflake/snowflake-cortex-agents/&quot;&gt;Cortex Agents&lt;/a&gt; makes it the obvious retrieval backbone. &lt;strong&gt;The catch is the serving meter that bills idle indexes&lt;/strong&gt;, so treat &lt;code&gt;AUTO_SUSPEND&lt;/code&gt; and right-sized chunks as setup, not afterthoughts. Get the chunking and the cost controls right up front and you have enterprise search and RAG without running a search stack. Skip them and you are paying rent on an index nobody is querying.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-search/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-search/cortex-search-overview&quot;&gt;Snowflake Documentation: Cortex Search overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-search/cortex-search-costs&quot;&gt;Snowflake Documentation: Understanding cost for Cortex Search Services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-cortex-search&quot;&gt;Snowflake Documentation: CREATE CORTEX SEARCH SERVICE&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Cortex Analyst: let business users query Snowflake in plain English</title>
    <link href="https://data-today.net/snowflake/snowflake-cortex-analyst/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-cortex-analyst/</id>
    <content type="html">&lt;p&gt;The most expensive bottleneck in most data teams is not compute, it is the queue. Business users have questions, only the analysts can write SQL, and every &amp;quot;quick number&amp;quot; becomes a ticket. &lt;strong&gt;Cortex Analyst&lt;/strong&gt; is Snowflake&#39;s answer: a fully managed text-to-SQL service where a business user asks &amp;quot;what was month-over-month revenue growth in EMEA last quarter&amp;quot; in plain English and gets a real answer, generated as SQL, run on your warehouse, with no analyst in the loop. It ships as a REST API so you can drop it into Slack, Teams, a Streamlit app, or your own product. The thing that decides whether it delights users or embarrasses you: &lt;strong&gt;the semantic view you build first.&lt;/strong&gt; Point it at a raw schema and it guesses; give it a semantic model and it gets the business logic right.&lt;/p&gt;
&lt;p&gt;This guide is for the data engineer who will be asked to &amp;quot;add AI to our analytics&amp;quot; and needs to know what Cortex Analyst really is, what makes it accurate, what it costs, and where it falls down.&lt;/p&gt;
&lt;h2 id=&quot;why-does-a-semantic-model-matter-so-much&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-analyst/#why-does-a-semantic-model-matter-so-much&quot;&gt;&lt;span&gt;Why does a semantic model matter so much?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Generic text-to-SQL fails in enterprises for a boring reason: a database schema does not contain business meaning. A column called &lt;code&gt;rev_amt&lt;/code&gt; does not tell a model that revenue excludes returns, that &amp;quot;EMEA&amp;quot; maps to a specific set of country codes, or that &amp;quot;active customer&amp;quot; has a precise definition your finance team agreed on. Hand a model just the schema and it hallucinates the business logic.&lt;/p&gt;
&lt;p&gt;Cortex Analyst closes that gap with a &lt;strong&gt;semantic view&lt;/strong&gt;, a schema-level Snowflake object that defines the business layer over your tables: logical tables for entities like customers and orders, dimensions for categorical context, facts for row-level numbers, metrics for the KPIs with their correct aggregation formulas, and the relationships that define how tables join. That metadata is what turns a vague question into the right SQL.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-cortex-analyst-fig.png&quot; alt=&quot;Bar chart of text-to-SQL accuracy: about 45 percent from raw schema, about 90 percent with a semantic view&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: giving Cortex Analyst a semantic view rather than a bare schema is the single biggest lever on answer accuracy. Source: Snowflake Cortex Analyst documentation on semantic models.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The practical consequence: &lt;strong&gt;the work is not the AI, it is the semantic model.&lt;/strong&gt; Snowflake handles the language model, the model selection, and the text-to-SQL machinery. Your job is to encode the business definitions once, well, so the answers are trustworthy. Skip that and you ship a confident liar.&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- A semantic view is the business layer Cortex Analyst reasons over.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- It names entities, the metrics with their real formulas, and join paths,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- so &quot;revenue&quot; means what finance means, not whatever a column is called.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; SEMANTIC &lt;span class=&quot;token keyword&quot;&gt;VIEW&lt;/span&gt; sales_analytics
  &lt;span class=&quot;token keyword&quot;&gt;TABLES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    orders &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; analytics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    customers &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; analytics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customers &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customer_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  RELATIONSHIPS &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    orders &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customer_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; customers &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customer_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  FACTS &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;line_total &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; quantity &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; unit_price&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  METRICS &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;orders&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;net_revenue &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;line_total&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;returned&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  DIMENSIONS &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; region&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can build it with the Semantic View Autopilot or hand-write the YAML, and you should seed it with verified example questions and their correct SQL, which Snowflake uses to guide generation and lets you measure accuracy over time.&lt;/p&gt;
&lt;h2 id=&quot;what-does-it-cost-and-how-is-that-different-from-raw-cortex&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-analyst/#what-does-it-cost-and-how-is-that-different-from-raw-cortex&quot;&gt;&lt;span&gt;What does it cost, and how is that different from raw Cortex?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where Cortex Analyst surprises people in a good way. Most Cortex AI functions bill &lt;strong&gt;per token&lt;/strong&gt;, so a long prompt costs more. Cortex Analyst bills &lt;strong&gt;per message&lt;/strong&gt; instead: each successful request (HTTP 200) counts as one unit, and the number of tokens does not affect the price unless you call it through Cortex Agents. Failed requests are not charged.&lt;/p&gt;
&lt;p&gt;The cost you must not forget is the second meter. Cortex Analyst&#39;s per-message charge covers only the text-to-SQL generation. &lt;strong&gt;The generated SQL then runs on your virtual warehouse, and that compute is billed separately.&lt;/strong&gt; So a chatty dashboard that fires hundreds of questions an hour costs you on two lines: the Analyst messages and the warehouse time to execute every query. Track the first with the &lt;code&gt;CORTEX_ANALYST_USAGE_HISTORY&lt;/code&gt; view in &lt;code&gt;ACCOUNT_USAGE&lt;/code&gt; and the second the same way you watch any warehouse, as covered in the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/&quot;&gt;warehouse sizing guide&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Right-size the warehouse behind it.&lt;/strong&gt; The questions are usually small aggregations, so a small warehouse with auto-suspend is plenty. You do not need a big cluster to answer &amp;quot;total revenue last month&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache the obvious.&lt;/strong&gt; If the same ten questions arrive all day, the generated SQL is deterministic enough to cache results upstream rather than re-running every time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Watch multi-turn cost.&lt;/strong&gt; Follow-up questions resend the whole conversation history on every turn, and the cost grows with each round, so long rambling sessions cost more than crisp ones.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-can-it-not-do-yet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-analyst/#what-can-it-not-do-yet&quot;&gt;&lt;span&gt;What can it not do yet?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Set expectations honestly with stakeholders, because Cortex Analyst is narrower than &amp;quot;ask anything&amp;quot;. It answers questions that can be resolved with &lt;strong&gt;SQL over your structured data&lt;/strong&gt;, and nothing else. It does not generate open-ended business insight: ask &amp;quot;what trends do you see&amp;quot; and it has no answer, because that is not a SQL query. It also cannot reference the results of a previous query, so &amp;quot;what is the revenue of the second product you just listed&amp;quot; breaks, since it does not have the earlier result set in hand. And very long, intent-shifting conversations degrade, at which point the fix is to reset and start clean.&lt;/p&gt;
&lt;p&gt;Governance is the part you can reassure security about. Cortex Analyst runs inside Snowflake&#39;s perimeter, the default models from Mistral and Meta keep data and prompts within Snowflake&#39;s governance boundary, it does not train on your data, and the generated SQL executes under the calling user&#39;s &lt;strong&gt;role-based access control&lt;/strong&gt;, so a user can never get an answer from data their role cannot see. Access is gated by the &lt;code&gt;SNOWFLAKE.CORTEX_ANALYST_USER&lt;/code&gt; database role, which you grant to a custom role rather than directly to users. For the broader access-control pattern, see the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/&quot;&gt;governance guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-honest-read&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-analyst/#the-honest-read&quot;&gt;&lt;span&gt;The honest read&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cortex Analyst is one of the few enterprise AI features where the value is real and the work is well understood: it moves the analyst queue off your team and onto a managed service, and it does so without your data leaving Snowflake. &lt;strong&gt;The catch is that it is only as good as the semantic model you invest in&lt;/strong&gt;, and that model is ordinary, unglamorous data-modelling work, not magic. Teams that treat the semantic view as the product ship something business users trust. Teams that point it at a raw schema and call it AI ship a demo that quietly gives wrong numbers, which is worse than no answer at all.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-analyst/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst&quot;&gt;Snowflake Documentation: Cortex Analyst&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/views-semantic/overview&quot;&gt;Snowflake Documentation: Overview of semantic views&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst#cost-considerations&quot;&gt;Snowflake Documentation: Cortex Analyst cost considerations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake Cortex: running LLMs where your data already lives</title>
    <link href="https://data-today.net/snowflake/snowflake-cortex-ai-functions/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-cortex-ai-functions/</id>
    <content type="html">&lt;p&gt;Every data team has been handed the same ask: &amp;quot;can we use AI on this?&amp;quot; The usual answer involves standing up a separate service, shipping data to an external API, and owning a new security review. Snowflake &lt;strong&gt;Cortex&lt;/strong&gt; removes most of that by exposing large language models as plain SQL functions that run inside the Snowflake perimeter. You call &lt;code&gt;AI_COMPLETE(&#39;llama3.1-70b&#39;, prompt)&lt;/code&gt; in a query, against data that never leaves your account, and get a result back in the same result set. The catch that decides your bill: these functions are &lt;strong&gt;billed per token by model, and the spread between a small model and a frontier one is roughly 40x&lt;/strong&gt;. Model choice is not a detail here, it is the budget.&lt;/p&gt;
&lt;p&gt;This guide is for the data engineer or data scientist who wants to add LLM work to a Snowflake pipeline without standing up new infrastructure, and who needs to know what is production-ready versus what is a demo.&lt;/p&gt;
&lt;h2 id=&quot;what-can-you-actually-call&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-functions/#what-can-you-actually-call&quot;&gt;&lt;span&gt;What can you actually call?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cortex ships LLM capability as two kinds of SQL function. The &lt;strong&gt;task-specific functions&lt;/strong&gt; do one job well with no prompt engineering: &lt;code&gt;AI_CLASSIFY&lt;/code&gt; sorts text or images into categories you define, &lt;code&gt;AI_FILTER&lt;/code&gt; returns true or false so you can use a model inside a &lt;code&gt;WHERE&lt;/code&gt; or &lt;code&gt;JOIN&lt;/code&gt;, &lt;code&gt;AI_SENTIMENT&lt;/code&gt; extracts sentiment, &lt;code&gt;AI_EXTRACT&lt;/code&gt; pulls structured fields out of text and documents, &lt;code&gt;AI_TRANSLATE&lt;/code&gt; localizes, and &lt;code&gt;AI_AGG&lt;/code&gt; and &lt;code&gt;AI_SUMMARIZE_AGG&lt;/code&gt; summarize across many rows without hitting a context-window limit. The &lt;strong&gt;general function&lt;/strong&gt; is &lt;code&gt;AI_COMPLETE&lt;/code&gt;, the one you reach for when you want a specific model to do an open-ended generation.&lt;/p&gt;
&lt;p&gt;The point that makes this worth using is that it is just SQL, so a model call composes with everything else you do in a query:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Triage support tickets in one pass: classify, score sentiment,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- and summarize, all inside the warehouse, no data leaving Snowflake.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
    ticket_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    AI_CLASSIFY&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;billing&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;bug&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;feature_request&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;churn_risk&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;:labels&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;::string &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; topic&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    AI_SENTIMENT&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;:categories&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;:sentiment::string &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; sentiment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    AI_COMPLETE&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;llama3.1-8b&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;Summarize this ticket in one sentence: &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; one_line
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; support_tickets
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; created_at &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; DATEADD&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;day&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To run any of this, the role needs the &lt;code&gt;USE AI FUNCTIONS&lt;/code&gt; account privilege plus the &lt;code&gt;CORTEX_USER&lt;/code&gt; database role. Models from OpenAI, Anthropic, Meta, Mistral, and DeepSeek are available depending on your region, and all of them run inside Snowflake&#39;s service perimeter rather than calling out to a third-party endpoint, which is the entire security argument for using Cortex over a raw API.&lt;/p&gt;
&lt;p&gt;Beyond the one-shot text functions, Cortex also covers the building blocks for retrieval. &lt;code&gt;AI_EMBED&lt;/code&gt; turns text or images into embedding vectors you can store in a &lt;code&gt;VECTOR&lt;/code&gt; column and search with &lt;code&gt;VECTOR_COSINE_SIMILARITY&lt;/code&gt;, which is the foundation of a retrieval-augmented generation pipeline that never leaves Snowflake. For teams that need more than SQL functions, &lt;strong&gt;Snowpark&lt;/strong&gt; runs custom Python, including your own models, on Snowflake compute, so the classic build-versus-buy line sits between a managed Cortex function and a Snowpark job you own end to end.&lt;/p&gt;
&lt;h2 id=&quot;what-does-it-cost-and-where-does-it-bite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-functions/#what-does-it-cost-and-where-does-it-bite&quot;&gt;&lt;span&gt;What does it cost, and where does it bite?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cortex AI functions are billed by &lt;strong&gt;tokens processed&lt;/strong&gt;, metered as Snowflake credits, and the rate depends on the model. That is the lever that dominates everything else.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-cortex-ai-functions-fig.png&quot; alt=&quot;Bar chart of relative Cortex cost per million tokens by model tier: small 1x, mid 9x, large frontier 40x&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: relative cost per million tokens climbs steeply with model size in Cortex AI_COMPLETE, roughly 1x for a small model, 9x mid, 40x frontier. Source: Snowflake Cortex documentation; check the current consumption table for exact per-model rates.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The practical consequence: defaulting every call to the biggest model is how a proof-of-concept turns into a budget incident. Most classification, sentiment, and extraction work runs fine on a small model, and the small models are where the per-token rate is a fraction of frontier. Reserve the large models for genuinely hard generation, and you can cut the bill by an order of magnitude without anyone noticing a quality drop. Three habits keep Cortex spend honest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Right-size the model per task.&lt;/strong&gt; Use a small model for classification and tagging; only escalate to a frontier model when the output quality demonstrably needs it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Count tokens before you run at scale.&lt;/strong&gt; &lt;code&gt;AI_COUNT_TOKENS&lt;/code&gt; tells you the token load of a prompt, so you can estimate the cost of a batch before you point it at a 50-million-row table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch, do not trickle.&lt;/strong&gt; Cortex functions are optimized for throughput over large tables. Running them row-by-row from an app is the slow, expensive path; for interactive latency Snowflake points you at the REST APIs instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Track spend with the Cortex functions in &lt;code&gt;ACCOUNT_USAGE&lt;/code&gt; so model cost lands in the same FinOps view as your warehouses. The same right-sizing instinct from the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/&quot;&gt;warehouse sizing guide&lt;/a&gt; applies here: the cheapest unit that does the job, not the biggest one available.&lt;/p&gt;
&lt;p&gt;One more cost trap worth naming: the prompt is part of the token count, not just the answer. Stuffing a 4,000-token system prompt and the full document into every row of a large table means you pay for that context on every single call. If you are classifying ten million rows, a 200-token prompt versus a 2,000-token prompt is a 10x difference on the input side alone. Trim the prompt, pass only the columns the model needs, and use the task-specific functions instead of hand-rolling the same job through &lt;code&gt;AI_COMPLETE&lt;/code&gt;, because they are tuned for exactly that work.&lt;/p&gt;
&lt;h2 id=&quot;what-is-production-ready-and-what-is-still-a-demo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-functions/#what-is-production-ready-and-what-is-still-a-demo&quot;&gt;&lt;span&gt;What is production-ready, and what is still a demo?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Be honest with stakeholders about the maturity line, because Cortex spans both sides of it. The task-specific functions and &lt;code&gt;AI_COMPLETE&lt;/code&gt; are generally available and fine to ship; they are SQL functions with predictable billing. Higher up the stack, &lt;strong&gt;Cortex Search&lt;/strong&gt; (retrieval) and &lt;strong&gt;Cortex Analyst&lt;/strong&gt; (natural-language-to-SQL) are powerful but deserve real evaluation before you put them in front of users, and some individual functions are still Preview features, which means they can change and should not anchor a production SLA. The rule: check whether the specific function you are calling is GA or Preview before it goes near a customer path. Generally available functions are safe to build on; Preview ones are for prototypes.&lt;/p&gt;
&lt;h2 id=&quot;the-number-to-watch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-functions/#the-number-to-watch&quot;&gt;&lt;span&gt;The number to watch&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Track credits per thousand Cortex calls, broken down by model. That single view exposes the most common failure mode, an expensive model quietly handling work a cheap one could do, and it turns &amp;quot;can we use AI on this?&amp;quot; into a question you can actually price. When the per-call cost is dominated by one frontier model on a high-volume task, that is your first optimization, not a bigger budget. Get that one number on a dashboard and the AI line in your Snowflake bill stops being a mystery.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-functions/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/llm-functions&quot;&gt;Snowflake Documentation: Cortex AI Functions (including LLM functions)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/aisql/managing-cost&quot;&gt;Snowflake Documentation: Managing AI Function costs with Account Usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/aisql/cost-considerations&quot;&gt;Snowflake Documentation: Cortex AI Functions cost considerations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Building an AI agent on your Snowflake data with Cortex Agents</title>
    <link href="https://data-today.net/snowflake/snowflake-cortex-agents/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-cortex-agents/</id>
    <content type="html">&lt;p&gt;Every enterprise that bought into chat-with-your-data quickly hit the same wall: a text-to-SQL tool answers questions about tables, a search tool answers questions about documents, and a real business question needs both at once. &amp;quot;Why did churn spike in EMEA last quarter, and what did the support tickets say&amp;quot; is half a SQL query and half a document search, stitched together with reasoning. &lt;strong&gt;Cortex Agents&lt;/strong&gt; is Snowflake&#39;s framework for exactly that: an AI agent that plans a multi-step task, calls the right tool for each step, reflects on the result, and keeps going until it has an answer, all inside Snowflake&#39;s governance boundary. It is the orchestration layer that sits above &lt;a href=&quot;https://data-today.net/snowflake/snowflake-cortex-analyst/&quot;&gt;Cortex Analyst&lt;/a&gt; and Cortex Search rather than replacing them.&lt;/p&gt;
&lt;p&gt;This guide is for the builder who has been asked to &amp;quot;build us an AI agent&amp;quot; on company data and needs to know what Cortex Agents actually does, how the loop works, what privileges it needs, and where the costs hide before you ship it.&lt;/p&gt;
&lt;h2 id=&quot;what-does-an-agent-do-that-a-single-cortex-call-does-not&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-agents/#what-does-an-agent-do-that-a-single-cortex-call-does-not&quot;&gt;&lt;span&gt;What does an agent do that a single Cortex call does not?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A plain Cortex call is one shot: a prompt in, a completion out. An agent runs a loop. Snowflake&#39;s orchestration follows a plan-act-reflect cycle that should be familiar to anyone who has built with agent frameworks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Planning.&lt;/strong&gt; The agent reads the request, explores what it knows, splits the task into steps, and routes each step to a tool. &amp;quot;Churn plus ticket sentiment&amp;quot; becomes a structured query step and a document search step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool use.&lt;/strong&gt; It calls the tools. Structured questions go to a &lt;strong&gt;Cortex Analyst&lt;/strong&gt; tool over your semantic view. Unstructured questions go to a &lt;strong&gt;Cortex Search&lt;/strong&gt; tool over indexed documents. It can also call custom tools you expose as stored procedures or UDFs, and a web-search tool backed by the Brave API with zero data retention.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reflection.&lt;/strong&gt; It evaluates the tool output, decides whether it has enough to answer or needs another step, and iterates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitor and respond.&lt;/strong&gt; It assembles the final answer and you can monitor, evaluate, and tune the whole trajectory.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The agent itself is a first-class Snowflake object, and it uses &lt;strong&gt;threads&lt;/strong&gt; to persist conversation context across turns, so a follow-up question keeps the earlier context instead of starting cold. You access it through the &lt;code&gt;agent:run&lt;/code&gt; REST API, which means the same agent can power a Streamlit app, an internal portal, or a product feature.&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- An agent is a Snowflake object that bundles an orchestration model&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- with the tools it is allowed to use. The model plans; the tools act.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; AGENT support_analyst
  &lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; PROFILE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;orchestration_model&quot;: &quot;auto&quot;}&#39;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;COMMENT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Answers questions across sales tables and support tickets&#39;&lt;/span&gt;
  TOOLS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    cortex_analyst_tool&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;semantic_view &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;sales_analytics&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    cortex_search_tool&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;service &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;support_tickets_search&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Setting the orchestration model to &lt;strong&gt;&lt;code&gt;auto&lt;/code&gt;&lt;/strong&gt; lets Snowflake pick, which is the recommended default; you can pin a specific model such as &lt;code&gt;claude-sonnet-4-5&lt;/code&gt; or &lt;code&gt;openai-gpt-4.1&lt;/code&gt; when you need predictable behaviour.&lt;/p&gt;
&lt;h2 id=&quot;what-does-it-cost-to-run&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-agents/#what-does-it-cost-to-run&quot;&gt;&lt;span&gt;What does it cost to run?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the question that decides whether your agent reaches production, and the honest answer is that an agent has no single price. &lt;strong&gt;A Cortex Agent bill is the sum of four separate meters&lt;/strong&gt;, and a careless agent can light up all four on every question.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-cortex-agents-fig.png&quot; alt=&quot;Bar chart of Cortex Agent cost components: orchestration tokens, Cortex Analyst tokens, Cortex Search index, warehouse run, each contributing a share of the total&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: a Cortex Agent combines four cost components rather than one, so a single question can bill on all four at once. Source: Snowflake Cortex Agents cost documentation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Meter&lt;/th&gt;
&lt;th&gt;What it charges for&lt;/th&gt;
&lt;th&gt;What drives it up&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Orchestration tokens&lt;/td&gt;
&lt;td&gt;The planning and reflection model&#39;s reasoning&lt;/td&gt;
&lt;td&gt;More steps, longer threads, bigger context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cortex Analyst tokens&lt;/td&gt;
&lt;td&gt;Each structured-data tool call&lt;/td&gt;
&lt;td&gt;Every SQL step the agent takes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cortex Search index&lt;/td&gt;
&lt;td&gt;Keeping the document index live&lt;/td&gt;
&lt;td&gt;Index size and persistence over time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warehouse run&lt;/td&gt;
&lt;td&gt;Executing the SQL the agent generates&lt;/td&gt;
&lt;td&gt;Query size and warehouse uptime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The trap is that an agent multiplies calls. A single user question can trigger several planning rounds, two or three tool calls, and a reflection pass, so what feels like &amp;quot;one question&amp;quot; is &lt;strong&gt;a dozen billed operations under the hood&lt;/strong&gt;. Watch the trajectory, cap the number of steps where you can, and keep threads from growing unbounded, because every turn resends accumulated context and the orchestration-token line climbs with it. The warehouse discipline from the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/&quot;&gt;warehouse sizing guide&lt;/a&gt; applies to the fourth meter unchanged.&lt;/p&gt;
&lt;h2 id=&quot;what-privileges-and-guardrails-does-it-need&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-agents/#what-privileges-and-guardrails-does-it-need&quot;&gt;&lt;span&gt;What privileges and guardrails does it need?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cortex Agents is governed like the rest of Snowflake, which is the reason to build the agent here rather than wiring an external LLM to a database connection. To create and run agents a role needs &lt;code&gt;SNOWFLAKE.CORTEX_USER&lt;/code&gt; (or the more specific &lt;code&gt;CORTEX_AGENT_USER&lt;/code&gt; database role) plus the object privileges to &lt;code&gt;CREATE AGENT&lt;/code&gt;, and &lt;code&gt;USAGE&lt;/code&gt;, &lt;code&gt;OWNERSHIP&lt;/code&gt;, &lt;code&gt;MODIFY&lt;/code&gt;, or &lt;code&gt;MONITOR&lt;/code&gt; on the agents themselves. Every tool the agent calls still runs under the caller&#39;s role, so the agent can never read data the user could not, the same boundary that protects &lt;a href=&quot;https://data-today.net/snowflake/snowflake-cortex-analyst/&quot;&gt;Cortex Analyst&lt;/a&gt; and is enforced by the &lt;a href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/&quot;&gt;RBAC and masking setup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Two operational caveats before you put an agent in front of users:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Accuracy is not guaranteed.&lt;/strong&gt; Snowflake is explicit that agent answers can be wrong and should be reviewed, especially for anything that drives a decision. Build a review step for high-stakes use, do not auto-execute on the agent&#39;s word.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runtime matters.&lt;/strong&gt; Agents are not supported from the Streamlit-in-Snowflake warehouse runtime; you run them in the container runtime instead. Get this wrong and your first deploy fails for an unobvious reason.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-honest-read&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-agents/#the-honest-read&quot;&gt;&lt;span&gt;The honest read&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cortex Agents is the right tool when a real question genuinely spans structured and unstructured data and you want the reasoning, the data, and the access control to stay in one governed place. That is a meaningful capability, and keeping it inside Snowflake&#39;s perimeter is a genuine advantage over bolting an external agent onto a database. &lt;strong&gt;The discipline it demands is cost observability&lt;/strong&gt;: four meters, a loop that multiplies calls, and answers you still have to verify. Build the semantic view and the search service well first, instrument the trajectory before you scale, and treat the agent as a powerful assistant that needs a reviewer, not an oracle you can trust unattended. The rest of the &lt;a href=&quot;https://data-today.net/snowflake/&quot;&gt;Snowflake guides&lt;/a&gt; cover the foundations an agent is only as good as.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-agents/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents&quot;&gt;Snowflake Documentation: Cortex Agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-run&quot;&gt;Snowflake Documentation: Cortex Agents run API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-search/cortex-search-overview&quot;&gt;Snowflake Documentation: Cortex Search overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake Adaptive Compute rewrites warehouse sizing</title>
    <link href="https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/</id>
    <content type="html">&lt;p&gt;Snowflake warehouse sizing used to be a small act of fiction. You picked a size, guessed at concurrency, argued about auto-suspend, and hoped next month’s bill did not punish last month’s optimism. Snowflake Adaptive Compute changes that bargain. It replaces fixed warehouse sizing with adaptive warehouses that set compute per query, bill by query usage, and expose only &lt;strong&gt;2 primary knobs&lt;/strong&gt;: &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; and &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The important correction: Snowflake’s June 2, 2026 blog says Snowflake Adaptive Compute is generally available soon, but the current &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive&quot;&gt;Snowflake Adaptive Compute documentation&lt;/a&gt; lists it as an Open Preview feature. For platform teams, that is the whole story in miniature. This is not just a faster warehouse type. It is a new operating model for Snowflake credits, observability, and accountability.&lt;/p&gt;
&lt;p&gt;If you already moved steady workloads to &lt;a href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/&quot;&gt;Snowflake Gen2 warehouses&lt;/a&gt;, Adaptive Compute is the next question you need to answer. Gen2 keeps the old control surface. Adaptive Compute asks you to let Snowflake schedule and scale inside an account-level compute pool, then prove whether the bill got better.&lt;/p&gt;
&lt;h2 id=&quot;what-actually-changes-when-you-create-an-adaptive-warehouse&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/#what-actually-changes-when-you-create-an-adaptive-warehouse&quot;&gt;&lt;span&gt;What actually changes when you create an adaptive warehouse?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An adaptive warehouse is still a Snowflake virtual warehouse from the user’s point of view. You &lt;code&gt;USE WAREHOUSE&lt;/code&gt;, run SQL, load data, and monitor usage in &lt;code&gt;SNOWFLAKE.ACCOUNT_USAGE&lt;/code&gt;. The difference is what you stop managing. Snowflake says adaptive warehouses remove manual warehouse size, multi-cluster settings, Query Acceleration Service settings, and suspend or resume policies from your tuning loop.&lt;/p&gt;
&lt;p&gt;The default create statement is deliberately boring:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; ADAPTIVE WAREHOUSE bi_adaptive_wh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That creates a warehouse with &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL = XLARGE&lt;/code&gt; and &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER = 2&lt;/code&gt;, according to the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#create-an-adaptive-warehouse&quot;&gt;SQL examples in Snowflake’s adaptive warehouse docs&lt;/a&gt;. Those defaults matter because they are not cosmetic. &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; is the upper bound Snowflake may apply for a single statement when it has high confidence an optimization helps. &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt; controls how much total query work can run at once relative to Snowflake’s computed baseline.&lt;/p&gt;
&lt;p&gt;Here is the version you should put in Terraform or a migration script when you want intent on the page:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; ADAPTIVE WAREHOUSE etl_adaptive_wh
  &lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; MAX_QUERY_PERFORMANCE_LEVEL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; LARGE
       QUERY_THROUGHPUT_MULTIPLIER &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;
       STATEMENT_QUEUED_TIMEOUT_IN_SECONDS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;
       STATEMENT_TIMEOUT_IN_SECONDS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The supported performance levels run from &lt;code&gt;XSMALL&lt;/code&gt; through &lt;code&gt;X4LARGE&lt;/code&gt;. A throughput multiplier is a non-negative integer, and &lt;code&gt;0&lt;/code&gt; means unlimited throughput. That last value is powerful and dangerous. In a FinOps review, &lt;strong&gt;0 should read as no instantaneous cap&lt;/strong&gt;, not as a clever shortcut.&lt;/p&gt;
&lt;p&gt;Snowflake’s claimed benchmark gains are large enough to justify a pilot, but not large enough to skip one. Its June 2026 blog reports Adaptive Compute gains of 1.6x for analytics, 2.2x for operational throughput, and 3.5x for DML-heavy workloads, based on TPC-DS and internal benchmarks measured in May 2026 against standard compute.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-adaptive-compute-sizing-fig-adaptive-benchmark-gains.png&quot; alt=&quot;Snowflake Adaptive Compute benchmark gains: analytics 1.6x faster, operational throughput 2.2x higher, and DML execution 3.5x faster.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Snowflake reported Adaptive Compute benchmark gains of 1.6x faster analytics, 2.2x higher operational throughput, and 3.5x faster DML execution, measured in May 2026.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Read the chart as a migration hypothesis, not as your savings forecast. The strongest number, &lt;strong&gt;3.5x faster DML execution&lt;/strong&gt;, points at pipelines, ingestion, and transformation workloads. The least surprising number, 1.6x faster analytics, still matters if your analysts live in ad hoc query land and your warehouse queue is a standing meeting with better snacks.&lt;/p&gt;
&lt;h2 id=&quot;how-is-snowflake-adaptive-compute-billed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/#how-is-snowflake-adaptive-compute-billed&quot;&gt;&lt;span&gt;How is Snowflake Adaptive Compute billed?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The billing change is the feature. Standard warehouses make you reason about size, run time, idle time, and cluster count. Adaptive warehouses use query-based billing. Snowflake says the cost of each query depends on compute and software resources used, including cluster sizes and capacity used by features like Query Acceleration Service. Creating the warehouse is free. Charges start when the first query runs.&lt;/p&gt;
&lt;p&gt;That shift kills one familiar FinOps metric: idle waste. On standard warehouses, &lt;code&gt;WAREHOUSE_METERING_HISTORY.CREDITS_ATTRIBUTED_COMPUTE_QUERIES&lt;/code&gt; helps separate query work from idle compute. Snowflake’s &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/warehouse_metering_history&quot;&gt;WAREHOUSE_METERING_HISTORY documentation&lt;/a&gt; says that column is &lt;code&gt;NULL&lt;/code&gt; for adaptive warehouses. So do not port your old idle-cost dashboard and call the migration measured.&lt;/p&gt;
&lt;p&gt;For adaptive warehouses, start at the query level:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
  query_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;credits_used&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; credits_used&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;credits_used_compute&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; compute_credits&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;credits_used_cloud_services&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; cloud_services_credits
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; SNOWFLAKE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ACCOUNT_USAGE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;QUERY_METERING_HISTORY
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; warehouse_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;BI_ADAPTIVE_WH&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; query_start_time &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; DATEADD&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; query_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; warehouse_name
&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; credits_used &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/query_metering_history&quot;&gt;QUERY_METERING_HISTORY view&lt;/a&gt; returns per-query credit usage for queries run on adaptive warehouses over the last 365 days, with view latency of up to 1 hour. That is the view your FinOps team should care about first. It lets you find the expensive query patterns that a warehouse-level total hides.&lt;/p&gt;
&lt;p&gt;Use warehouse metering for the monthly control plane:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
  warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  DATE_TRUNC&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; start_time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; usage_day&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;credits_used&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; total_credits&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;credits_used_compute&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; compute_credits
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; SNOWFLAKE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ACCOUNT_USAGE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;WAREHOUSE_METERING_HISTORY
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; warehouse_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;BI_ADAPTIVE_WH&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; start_time &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; DATEADD&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; usage_day
&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; usage_day&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The old question was whether an &lt;code&gt;XLARGE&lt;/code&gt; warehouse sat idle. The new question is whether an &lt;code&gt;XLARGE&lt;/code&gt; performance cap let a handful of queries consume more instantaneous compute than your service-level objective deserved.&lt;/p&gt;
&lt;h2 id=&quot;which-workloads-should-you-move-first&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/#which-workloads-should-you-move-first&quot;&gt;&lt;span&gt;Which workloads should you move first?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start with workloads where static sizing is already lying to you. Snowflake’s docs call out analytics, data loading pipelines, mixed BI and ETL, high size variance, and occasional HTAP queries as adaptive warehouse candidates. They also say you may prefer Gen2 for workloads that need direct sizing control, interactive warehouses for very low latency dashboards or applications, and Snowpark-optimized warehouses for high-memory Snowpark or ML workloads.&lt;/p&gt;
&lt;p&gt;A practical migration order looks like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;First adaptive setting to test&lt;/th&gt;
&lt;th&gt;Why it belongs in the pilot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bursty BI plus ad hoc SQL&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL = XLARGE&lt;/code&gt;, multiplier &lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Matches the default and tests whether queues fall without manual multi-cluster tuning.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost-sensitive ELT&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL = MEDIUM&lt;/code&gt;, multiplier &lt;code&gt;4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lets more work run while capping per-statement optimization.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DML-heavy pipelines&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL = LARGE&lt;/code&gt;, multiplier &lt;code&gt;4&lt;/code&gt; or &lt;code&gt;6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Snowflake reports the largest benchmark gain here: 3.5x faster DML execution.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User-facing low-latency apps&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Do not start here&lt;/td&gt;
&lt;td&gt;Snowflake points those to interactive warehouses, not adaptive warehouses.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The table is intentionally conservative. Adaptive Compute is Open Preview, requires Enterprise Edition or higher, and is currently limited in Snowflake’s docs to AWS US West 2 (Oregon), EU West 1 (Ireland), and AP Northeast 1 (Tokyo). That is enough to run serious tests. It is not enough to rewrite every warehouse standard across a global estate on Monday morning.&lt;/p&gt;
&lt;p&gt;The most interesting candidate is the messy shared warehouse you already dislike. The one with BI dashboards at 9 a.m., analyst exploration at noon, and transformation work after someone forgot to reschedule a task. Adaptive Compute’s account-level shared pool is built for that mess. It routes jobs from all adaptive warehouses in the account to a dedicated pool that is not shared with other accounts or other warehouse types.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-convert-without-breaking-running-queries&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/#how-do-you-convert-without-breaking-running-queries&quot;&gt;&lt;span&gt;How do you convert without breaking running queries?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake says converting a standard warehouse to or from adaptive is an online operation. Existing queries continue on the old compute resources, while new queries use the new warehouse type. During that overlap, Snowflake says you are charged for both sets of compute resources.&lt;/p&gt;
&lt;p&gt;That detail deserves a runbook line in bold: &lt;strong&gt;convert during a quiet window even when the operation is online&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The SQL is simple:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE bi_wh &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; WAREHOUSE_TYPE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ADAPTIVE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rolling back is just as direct:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE bi_wh &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; WAREHOUSE_TYPE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;STANDARD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On conversion, Snowflake computes adaptive values from the existing warehouse size, &lt;code&gt;MAX_CLUSTER_COUNT&lt;/code&gt;, Query Acceleration Service scale factor, and warehouse generation. After conversion, standard properties such as &lt;code&gt;WAREHOUSE_SIZE&lt;/code&gt;, &lt;code&gt;MIN_CLUSTER_COUNT&lt;/code&gt;, &lt;code&gt;MAX_CLUSTER_COUNT&lt;/code&gt;, and &lt;code&gt;SCALING_POLICY&lt;/code&gt; no longer apply. Adaptive properties do not apply after converting back to standard.&lt;/p&gt;
&lt;p&gt;You can inspect the new state with &lt;code&gt;SHOW WAREHOUSES&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SHOW&lt;/span&gt; WAREHOUSES &lt;span class=&quot;token operator&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;BI_WH&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For adaptive warehouses, Snowflake adds columns such as &lt;code&gt;STATE&lt;/code&gt;, &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt;, &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt;, and &lt;code&gt;DISABLED_REASONS&lt;/code&gt;. &lt;code&gt;STATE&lt;/code&gt; is &lt;code&gt;ENABLED&lt;/code&gt; or &lt;code&gt;DISABLED&lt;/code&gt;, which is separate from the old mental model of a warehouse being suspended.&lt;/p&gt;
&lt;p&gt;There are hard conversion limits. Snowflake’s docs say conversions to or from &lt;code&gt;X5LARGE&lt;/code&gt; or &lt;code&gt;X6LARGE&lt;/code&gt; are not supported, and neither are conversions to or from Snowpark-optimized or interactive warehouses. If you run those, create a new adaptive warehouse for testing instead of trying to be clever with &lt;code&gt;ALTER&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-should-your-cost-guardrails-look-like&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/#what-should-your-cost-guardrails-look-like&quot;&gt;&lt;span&gt;What should your cost guardrails look like?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Do not hand Adaptive Compute to every team with &lt;code&gt;CREATE WAREHOUSE&lt;/code&gt;. The control surface is smaller, which makes the blast radius easier to miss. &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER = 0&lt;/code&gt; can remove the throughput cap, and a high &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; can raise per-query spend when Snowflake believes optimization will help.&lt;/p&gt;
&lt;p&gt;Start with roles:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; WAREHOUSE &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; ACCOUNT &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE platform_compute_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;USAGE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; WAREHOUSE bi_adaptive_wh &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE bi_analyst&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; MONITOR &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; WAREHOUSE bi_adaptive_wh &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE finops_analyst&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; OPERATE &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; WAREHOUSE bi_adaptive_wh &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE platform_operator&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Snowflake’s access control docs say &lt;code&gt;CREATE WAREHOUSE&lt;/code&gt; is required at the account level, while warehouse privileges include &lt;code&gt;USAGE&lt;/code&gt;, &lt;code&gt;MONITOR&lt;/code&gt;, &lt;code&gt;OPERATE&lt;/code&gt;, &lt;code&gt;MODIFY&lt;/code&gt;, and &lt;code&gt;OWNERSHIP&lt;/code&gt;. Keep &lt;code&gt;MODIFY&lt;/code&gt; away from workload teams unless you want multiplier changes to become the new shadow scaling policy.&lt;/p&gt;
&lt;p&gt;Then track queuing and latency before you raise the multiplier:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
  DATE_TRUNC&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;hour&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; start_time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; hour_start&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;AVG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queued_overload_time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; avg_queued_overload_ms&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;AVG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;total_elapsed_time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; avg_elapsed_ms&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; query_count
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; SNOWFLAKE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ACCOUNT_USAGE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;QUERY_HISTORY
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; warehouse_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;BI_ADAPTIVE_WH&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; start_time &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; DATEADD&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; hour_start&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; warehouse_name
&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; hour_start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;queued_overload_time&lt;/code&gt; stays high, increase &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt; one step and watch query-level credits. If credits spike while latency barely moves, lower the cap. This is the new tuning loop. It is less warehouse babysitting, but it is not zero governance.&lt;/p&gt;
&lt;p&gt;A controlled adjustment looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE bi_adaptive_wh &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt;
  MAX_QUERY_PERFORMANCE_LEVEL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; LARGE
  QUERY_THROUGHPUT_MULTIPLIER &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For production, pair that with a resource monitor or Snowflake budget. Snowflake says the same cost tools work with adaptive warehouses, including budgets, resource monitors, &lt;code&gt;QUERY_METERING_HISTORY&lt;/code&gt;, and &lt;code&gt;WAREHOUSE_METERING_HISTORY&lt;/code&gt;. The point is to govern total spend over time while the warehouse adapts inside those guardrails.&lt;/p&gt;
&lt;h2 id=&quot;what-should-you-do-before-moving-production-spend&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/#what-should-you-do-before-moving-production-spend&quot;&gt;&lt;span&gt;What should you do before moving production spend?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run a two-week A/B pilot, not a belief exercise. Pick one existing warehouse with volatile demand. Clone the workload routing, set query tags, and compare p50, p95, total credits, credits per successful query, and queued time. Use the same 7-day and 30-day windows on both sides. Snowflake’s benchmark chart is useful because it tells you where to look first: analytics at 1.6x, operational throughput at 2.2x, and DML execution at 3.5x.&lt;/p&gt;
&lt;p&gt;Your acceptance criteria should fit on one screen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Credits per business event fall, or latency falls enough to justify flat credits.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;QUERY_METERING_HISTORY&lt;/code&gt; identifies the top 10 query patterns by adaptive spend.&lt;/li&gt;
&lt;li&gt;No team can change &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; or &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt; without platform approval.&lt;/li&gt;
&lt;li&gt;Preview-region and Enterprise Edition constraints match the accounts you plan to use.&lt;/li&gt;
&lt;li&gt;Rollback to &lt;code&gt;WAREHOUSE_TYPE = &#39;STANDARD&#39;&lt;/code&gt; has been tested once, not merely admired in a doc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The feature is promising because it moves Snowflake closer to the way teams actually run data platforms: mixed workloads, uneven demand, and bills that need attribution below the warehouse. The lock-in is also plain. You are outsourcing more scheduling intelligence to Snowflake, and your cost model becomes more Snowflake-specific at the query level.&lt;/p&gt;
&lt;p&gt;That trade can be worth it. Just make Snowflake earn the credits query by query.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive&quot;&gt;Snowflake Documentation: Adaptive Compute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.snowflake.com/en/blog/adaptive-compute-performance/&quot;&gt;Snowflake Blog: Adaptive Compute Delivers High Performance That Evolves with Your Workloads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/query_metering_history&quot;&gt;Snowflake Documentation: QUERY_METERING_HISTORY view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/warehouse_metering_history&quot;&gt;Snowflake Documentation: WAREHOUSE_METERING_HISTORY view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-warehouse&quot;&gt;Snowflake Documentation: CREATE WAREHOUSE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/alter-warehouse&quot;&gt;Snowflake Documentation: ALTER WAREHOUSE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/release-notes/preview-features&quot;&gt;Snowflake Documentation: Preview features&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake Adaptive Compute: a bill owner&#39;s guide</title>
    <link href="https://data-today.net/snowflake/snowflake-adaptive-compute-costs/" />
    <updated>2026-06-07T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-adaptive-compute-costs/</id>
    <content type="html">&lt;p&gt;Snowflake warehouse sizing used to be a tax you paid in meetings, runbooks, and Slack threads. Someone asks whether the finance dashboard should be on Medium or Large. Someone else asks why the ELT warehouse queued for 11 minutes at 8:05 a.m. Then the bill arrives and everybody rediscovers &lt;code&gt;AUTO_SUSPEND&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Snowflake Adaptive Compute is Snowflake&#39;s attempt to make that whole ritual optional.&lt;/strong&gt; It replaces fixed warehouse sizing with an adaptive warehouse that chooses compute per query, while you set two guardrails: &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; and &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt;. The catch is the same as the gift: Snowflake hides more of the machinery, and during public preview it does not give you per query cost visibility.&lt;/p&gt;
&lt;p&gt;Snowflake lists Adaptive Compute as an &lt;a href=&quot;https://docs.snowflake.com/en/release-notes/preview-features&quot;&gt;open preview feature introduced in April 2026&lt;/a&gt;, and its documentation says it currently requires Enterprise Edition or higher and is available only in 3 AWS regions: US West 2 Oregon, EU West 1 Ireland, and AP Northeast 1 Tokyo. That makes this a migration candidate for real workloads, but not a blind replacement for your most politically sensitive warehouse.&lt;/p&gt;
&lt;p&gt;If you already read our guide to &lt;a href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-sizing/&quot;&gt;how Snowflake Adaptive Compute rewrites warehouse sizing&lt;/a&gt;, treat this as the bill owner&#39;s companion piece: how it works, what to monitor, and where the control moves.&lt;/p&gt;
&lt;h2 id=&quot;what-did-snowflake-actually-change-in-the-warehouse-model&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-costs/#what-did-snowflake-actually-change-in-the-warehouse-model&quot;&gt;&lt;span&gt;What did Snowflake actually change in the warehouse model?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Adaptive Compute gives you a new warehouse type, not a new SQL engine you call directly. You create an adaptive warehouse, point sessions and jobs at it, and Snowflake routes queries into an account dedicated compute pool. Snowflake says that pool is not shared with other accounts, but it is separate from your standard and Snowpark optimized warehouses.&lt;/p&gt;
&lt;p&gt;The basic DDL is intentionally boring:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; ADAPTIVE WAREHOUSE wh_adaptive_bi&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That creates an adaptive warehouse with Snowflake&#39;s documented defaults: &lt;strong&gt;&lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL = XLARGE&lt;/code&gt; and &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER = 2&lt;/code&gt;&lt;/strong&gt;. You can also use the standard warehouse syntax with &lt;code&gt;WAREHOUSE_TYPE = &#39;ADAPTIVE&#39;&lt;/code&gt;, which matters if your provisioning code already emits &lt;code&gt;CREATE WAREHOUSE&lt;/code&gt; statements. Snowflake documents both forms in its &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive&quot;&gt;Adaptive Compute SQL reference&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; WAREHOUSE wh_adaptive_bi
  &lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; WAREHOUSE_TYPE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ADAPTIVE&#39;&lt;/span&gt;
       MAX_QUERY_PERFORMANCE_LEVEL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; LARGE
       QUERY_THROUGHPUT_MULTIPLIER &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What disappears is the old sizing choreography. You no longer set &lt;code&gt;WAREHOUSE_SIZE&lt;/code&gt;, &lt;code&gt;MIN_CLUSTER_COUNT&lt;/code&gt;, &lt;code&gt;MAX_CLUSTER_COUNT&lt;/code&gt;, &lt;code&gt;SCALING_POLICY&lt;/code&gt;, or a separate Query Acceleration Service scale factor on the adaptive warehouse. Snowflake&#39;s docs are explicit that standard warehouse properties such as &lt;code&gt;WAREHOUSE_SIZE&lt;/code&gt;, &lt;code&gt;MIN_CLUSTER_COUNT&lt;/code&gt;, &lt;code&gt;MAX_CLUSTER_COUNT&lt;/code&gt;, and &lt;code&gt;SCALING_POLICY&lt;/code&gt; cannot be set on an adaptive warehouse.&lt;/p&gt;
&lt;p&gt;The chart below counts the configuration surface that matters for day to day tuning. It is illustrative, but the inputs come from Snowflake&#39;s documented properties: a standard warehouse exposes the usual size, cluster, scaling, and QAS controls, while an adaptive warehouse exposes 2 primary controls.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-adaptive-compute-costs-fig-adaptive-knobs.png&quot; alt=&quot;Illustrative comparison for Snowflake Adaptive Compute: standard warehouses show 4 common tuning controls, adaptive warehouses show 2 primary controls.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: Standard warehouses expose 4 common tuning controls in this comparison, while Snowflake Adaptive Compute exposes 2 primary controls: MAX_QUERY_PERFORMANCE_LEVEL and QUERY_THROUGHPUT_MULTIPLIER.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;That reduction is the product bet. Snowflake is saying most teams do not really want finer grained knobs. They want bounded latency, bounded spend, and fewer 9 a.m. warehouse autopsies.&lt;/p&gt;
&lt;p&gt;The two remaining knobs are worth reading literally:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Control&lt;/th&gt;
&lt;th&gt;Applies to&lt;/th&gt;
&lt;th&gt;Default or special value&lt;/th&gt;
&lt;th&gt;What it really limits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adaptive warehouse&lt;/td&gt;
&lt;td&gt;&lt;code&gt;XLARGE&lt;/code&gt; default&lt;/td&gt;
&lt;td&gt;Upper bound for a single statement&#39;s performance level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adaptive warehouse&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt; default&lt;/td&gt;
&lt;td&gt;Burst throughput as a multiplier over Snowflake&#39;s computed minimum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER = 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adaptive warehouse&lt;/td&gt;
&lt;td&gt;Special value &lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unlimited throughput, subject to available capacity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WAREHOUSE_SIZE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Standard warehouse&lt;/td&gt;
&lt;td&gt;&lt;code&gt;XSMALL&lt;/code&gt; default in standard &lt;code&gt;CREATE WAREHOUSE&lt;/code&gt; docs&lt;/td&gt;
&lt;td&gt;Fixed cluster size for a running warehouse&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The important word is cap. Setting &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL = XLARGE&lt;/code&gt; does not mean every tiny lookup burns XLARGE equivalent resources. Snowflake says smaller queries can run below the cap when they do not need that much compute. That is why this is not just auto resize with a fresh coat of paint.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-migrate-without-breaking-jobs-or-chargeback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-costs/#how-do-you-migrate-without-breaking-jobs-or-chargeback&quot;&gt;&lt;span&gt;How do you migrate without breaking jobs or chargeback?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The clean migration path is conversion in place. Snowflake documents that converting to or from an adaptive warehouse is an online operation: running queries continue on existing compute, while new queries use the new warehouse type. The warehouse name survives, which is more important than it sounds if your dbt profiles, Airflow DAGs, BI connections, and stored procedures have warehouse names hardcoded.&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE wh_bi_prod &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; WAREHOUSE_TYPE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ADAPTIVE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Snowflake automatically derives the adaptive values from the old warehouse&#39;s size, &lt;code&gt;MAX_CLUSTER_COUNT&lt;/code&gt;, QAS scale factor, and generation. That is a sensible first move because it preserves the intent of the old shape. It is not a reason to skip review.&lt;/p&gt;
&lt;p&gt;After conversion, inspect the visible properties:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SHOW&lt;/span&gt; WAREHOUSES &lt;span class=&quot;token operator&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;WH_BI_PROD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Snowflake adds adaptive specific &lt;code&gt;SHOW WAREHOUSES&lt;/code&gt; columns such as &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt;, &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt;, &lt;code&gt;STATE&lt;/code&gt;, and &lt;code&gt;DISABLED_REASONS&lt;/code&gt;. Properties that no longer apply show as &lt;code&gt;NULL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If the derived values are too generous for a dashboard warehouse, bring them down before the business discovers a new definition of interactive:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE wh_bi_prod &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt;
  MAX_QUERY_PERFORMANCE_LEVEL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; LARGE
  QUERY_THROUGHPUT_MULTIPLIER &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the migration goes sideways, you can convert back:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE wh_bi_prod &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; WAREHOUSE_TYPE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;STANDARD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is one billing wrinkle in the conversion path that deserves a bright yellow sticky note. Snowflake says that while old queries finish and new queries run on the new warehouse type, &lt;strong&gt;you are charged for both sets of compute resources&lt;/strong&gt;. For a quiet BI warehouse that may be noise. For a heavy ETL warehouse with 2 hour transformations already running, choose the migration window with intent.&lt;/p&gt;
&lt;p&gt;Do not convert unsupported shapes. During preview, Snowflake says you cannot convert to or from X5Large or X6Large warehouses, Snowpark optimized warehouses, or interactive warehouses. That means a compute heavy Snowpark workload should stay where it is unless Snowflake broadens support.&lt;/p&gt;
&lt;h2 id=&quot;how-is-adaptive-compute-billed-and-what-can-you-prove-today&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-costs/#how-is-adaptive-compute-billed-and-what-can-you-prove-today&quot;&gt;&lt;span&gt;How is Adaptive Compute billed, and what can you prove today?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Adaptive warehouses use query based billing. That sounds like a clean break from classic warehouse uptime billing, but Snowflake still reports the usage as virtual warehouse credits under compute. You are not charged for creating an adaptive warehouse. Charges start when the first query runs.&lt;/p&gt;
&lt;p&gt;This is the cost model in one sentence: &lt;strong&gt;you manage spend with caps and monitors, not with idle time math&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That is a meaningful change for teams that spent years training everyone to fear idle warehouses. On a standard warehouse, the size determines the compute resources in each cluster and therefore the credits consumed while the warehouse is running. On an adaptive warehouse, Snowflake says each query&#39;s cost depends on compute and software resources used, including cluster sizes and additional capacity used by features like QAS.&lt;/p&gt;
&lt;p&gt;Here is the part finance will ask about first: QAS does not show up as a separate adaptive warehouse credit line during preview. Snowflake says QAS usage is included in compute credits for adaptive warehouses. That simplifies showback, but it also removes a familiar line item you may have used to explain spikes.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;WAREHOUSE_METERING_HISTORY&lt;/code&gt; for daily warehouse level credits:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
  start_time::&lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; usage_date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;credits_used&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; credits_used
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; snowflake&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account_usage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;warehouse_metering_history
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; warehouse_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;WH_BI_PROD&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; start_time &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; DATEADD&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use &lt;code&gt;QUERY_HISTORY&lt;/code&gt; to confirm that the workload is actually running as adaptive, and to watch latency and queuing:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
  warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;COUNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; queries&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;AVG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;total_elapsed_time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; avg_elapsed_ms&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;AVG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queued_overload_time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; avg_queued_overload_ms
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; snowflake&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account_usage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;query_history
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; warehouse_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;WH_BI_PROD&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; warehouse_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ADAPTIVE&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; start_time &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; DATEADD&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Snowflake&#39;s docs also recommend &lt;code&gt;WAREHOUSE_LOAD_HISTORY&lt;/code&gt; for queuing behavior. That is the view you should wire into an alert before you increase the throughput multiplier:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
  start_time&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  avg_running&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  avg_queued_load
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; snowflake&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account_usage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;warehouse_load_history
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; warehouse_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;WH_BI_PROD&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; start_time &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; DATEADD&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;hour&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; start_time&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What you cannot prove yet is per query cost. Snowflake says query level cost visibility is not available during public preview and is planned for general availability. That is the biggest practical reason to pilot Adaptive Compute on workloads with good warehouse level ownership. If 12 teams share one warehouse, adaptive billing will not magically produce clean accountability.&lt;/p&gt;
&lt;h2 id=&quot;when-is-adaptive-compute-better-than-gen2-and-when-is-it-just-less-control&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-costs/#when-is-adaptive-compute-better-than-gen2-and-when-is-it-just-less-control&quot;&gt;&lt;span&gt;When is Adaptive Compute better than Gen2, and when is it just less control?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Gen2 warehouses and Adaptive Compute solve different problems. Gen2 keeps the familiar fixed warehouse model and improves the engine and hardware under it. Adaptive Compute changes the operating model.&lt;/p&gt;
&lt;p&gt;Snowflake&#39;s 2025 product blog said Standard Warehouse Generation 2 delivered &lt;strong&gt;2.1x faster performance for core analytics workloads over the 12 months ending May 2, 2025&lt;/strong&gt;, and positioned Adaptive Compute as the next step toward less infrastructure tuning. If you moved to Gen2 and got the performance you needed, you do not have to treat Adaptive Compute as an emergency migration.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;Status or number&lt;/th&gt;
&lt;th&gt;What you still tune&lt;/th&gt;
&lt;th&gt;Billing behavior&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Standard warehouse Gen1&lt;/td&gt;
&lt;td&gt;Default generation &lt;code&gt;1&lt;/code&gt; in &lt;code&gt;CREATE WAREHOUSE&lt;/code&gt; docs&lt;/td&gt;
&lt;td&gt;Size, clusters, scaling, suspend, QAS&lt;/td&gt;
&lt;td&gt;Credits while the warehouse runs&lt;/td&gt;
&lt;td&gt;Stable workloads with tight manual control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard warehouse Gen2&lt;/td&gt;
&lt;td&gt;Snowflake cited 2.1x faster core analytics performance in 2025&lt;/td&gt;
&lt;td&gt;Same warehouse model, newer generation&lt;/td&gt;
&lt;td&gt;Credits while the warehouse runs&lt;/td&gt;
&lt;td&gt;Existing warehouses that need faster execution without model change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adaptive warehouse&lt;/td&gt;
&lt;td&gt;Open preview introduced April 2026&lt;/td&gt;
&lt;td&gt;2 primary knobs&lt;/td&gt;
&lt;td&gt;Query based compute credits&lt;/td&gt;
&lt;td&gt;Variable concurrency where tuning overhead is the pain&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The strongest fit is a warehouse where the hard problem is workload variance: Monday dashboards, hourly ELT bursts, ad hoc analyst queries, and the occasional monster join. Adaptive Compute can choose resources per query and let you cap the worst case.&lt;/p&gt;
&lt;p&gt;The weaker fit is a warehouse where you need deterministic cost attribution or a tightly reasoned performance envelope. If a regulated team asks why one query cost what it cost, preview Adaptive Compute may not satisfy them yet. You can show warehouse level credits and query level timing. You cannot show query level credits.&lt;/p&gt;
&lt;p&gt;There is also a lock in angle. With standard warehouses, the mental model maps to other platforms: cluster size, concurrency, queueing, idle time. With Adaptive Compute, the most important scheduling logic is Snowflake proprietary. That may be fine. Most teams are not looking to lovingly hand tune cluster topology. But if your internal platform team has built a router that assigns queries to warehouses based on fingerprints, SLAs, and chargeback tags, Adaptive Compute competes with part of that control plane.&lt;/p&gt;
&lt;h2 id=&quot;how-should-you-lock-it-down-before-the-pilot-grows-legs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-costs/#how-should-you-lock-it-down-before-the-pilot-grows-legs&quot;&gt;&lt;span&gt;How should you lock it down before the pilot grows legs?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start with roles. Adaptive warehouses are still warehouses, so do not give every enthusiastic analyst the ability to create or modify them. Snowflake&#39;s &lt;code&gt;CREATE WAREHOUSE&lt;/code&gt; docs say the account level &lt;code&gt;CREATE WAREHOUSE&lt;/code&gt; privilege is required to create warehouses, and only &lt;code&gt;SYSADMIN&lt;/code&gt; or higher has it by default.&lt;/p&gt;
&lt;p&gt;A simple pattern is one owner role, one operator role, and one user role:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; ROLE adaptive_wh_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; ROLE adaptive_wh_operator&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; ROLE adaptive_wh_user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; WAREHOUSE &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; ACCOUNT &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE adaptive_wh_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the admin creates the warehouse, grant usage widely and modification narrowly:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;USAGE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; WAREHOUSE wh_bi_prod &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE adaptive_wh_user&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; MONITOR &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; WAREHOUSE wh_bi_prod &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE adaptive_wh_operator&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; OPERATE &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; WAREHOUSE wh_bi_prod &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE adaptive_wh_operator&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; WAREHOUSE wh_bi_prod &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE adaptive_wh_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That split matters because &lt;code&gt;MODIFY&lt;/code&gt; can change cost affecting properties. &lt;code&gt;OPERATE&lt;/code&gt; can change state, including warehouse operations. For adaptive warehouses, Snowflake also supports &lt;code&gt;ENABLE&lt;/code&gt; and &lt;code&gt;DISABLE&lt;/code&gt;; disabling rejects new jobs while already running queries continue.&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE wh_bi_prod &lt;span class=&quot;token keyword&quot;&gt;DISABLE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE wh_bi_prod &lt;span class=&quot;token keyword&quot;&gt;ENABLE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use this for preview blast radius. A disabled adaptive warehouse is a cleaner stop sign than dropping a warehouse that your jobs still reference.&lt;/p&gt;
&lt;p&gt;Then add a resource monitor or budget. Snowflake says existing budgets and resource monitors work with adaptive warehouses. The product story is automatic performance. Your job is automatic regret prevention.&lt;/p&gt;
&lt;p&gt;A practical pilot plan looks like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pick 1 warehouse with a clear owner and at least 14 days of baseline history in &lt;code&gt;WAREHOUSE_METERING_HISTORY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Convert in a low traffic window, especially if long queries are already running.&lt;/li&gt;
&lt;li&gt;Keep &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt; at the derived value or the default 2 for the first week unless &lt;code&gt;WAREHOUSE_LOAD_HISTORY&lt;/code&gt; shows sustained queueing.&lt;/li&gt;
&lt;li&gt;Do not use &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER = 0&lt;/code&gt; on a shared production warehouse unless a resource monitor is already attached.&lt;/li&gt;
&lt;li&gt;Report weekly on credits, query count, average elapsed time, and average queued overload time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is boring FinOps. Boring is the point.&lt;/p&gt;
&lt;h2 id=&quot;so-is-this-the-end-of-warehouse-sizing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-costs/#so-is-this-the-end-of-warehouse-sizing&quot;&gt;&lt;span&gt;So is this the end of warehouse sizing?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For many teams, yes, eventually. Snowflake Adaptive Compute moves the warehouse decision from &amp;quot;what size should this be?&amp;quot; to &amp;quot;what is the largest single query we are willing to fund, and how much burst do we allow?&amp;quot; That is a better conversation for most data teams.&lt;/p&gt;
&lt;p&gt;But the preview version is not a blank check. It is available in 3 AWS regions, requires Enterprise Edition or higher, excludes several warehouse types, and lacks per query credit visibility. If you own the Snowflake bill, your first move should be a measured pilot, not a fleet wide conversion script.&lt;/p&gt;
&lt;p&gt;The best use of Adaptive Compute is not to save you from understanding cost. It is to stop spending human time on knobs that Snowflake can probably tune better than your Tuesday afternoon hunch.&lt;/p&gt;
&lt;h2 id=&quot;sources&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-costs/#sources&quot;&gt;&lt;span&gt;Sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive&quot;&gt;Snowflake Documentation: Adaptive Compute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/release-notes/preview-features&quot;&gt;Snowflake Documentation: Preview features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-warehouse&quot;&gt;Snowflake Documentation: CREATE WAREHOUSE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/alter-warehouse&quot;&gt;Snowflake Documentation: ALTER WAREHOUSE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/security-access-control-privileges&quot;&gt;Snowflake Documentation: Access control privileges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.snowflake.com/en/blog/adaptive-compute-smarter-warehouses/&quot;&gt;Snowflake Blog: Introducing Even Easier-to-Use Snowflake Adaptive Compute with Better Price/Performance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
</feed>