<?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-08-10T00:00:00Z</updated>
  <id>https://data-today.net/</id>
  <author>
    <name>Data Today Newsroom</name>
  </author>
  <entry>
    <title>Snowflake DCM Projects GA: declarative IaC inside the warehouse</title>
    <link href="https://data-today.net/snowflake/snowflake-dcm-projects-declarative-iac/" />
    <updated>2026-08-10T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-dcm-projects-declarative-iac/</id>
    <content type="html">&lt;p&gt;Snowflake has shipped plenty of features for running code inside its warehouses, but until now it left the deployment of the warehouse objects themselves to third-party tools. That changes with Snowflake DCM Projects, which reached general availability on August 7, 2026. DCM, short for Database Change Management, lets you define databases, tables, tasks, and other Snowflake objects declaratively in SQL files, then let Snowflake figure out the diff and apply the changes. The headline: &lt;strong&gt;you can now version-control and idempotently deploy your Snowflake infrastructure without an external state file or a separate Terraform runner&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The move matters because every team running Snowflake at scale already has a deployment problem. Some use Terraform or dbt, some run hand-rolled SQL scripts in GitHub Actions, and most have a tangled mix of both. DCM Projects is Snowflake&#39;s native answer: a declarative layer that handles the plan, the diff, and the apply, all inside the account. For teams that already think about &lt;a href=&quot;https://data-today.net/snowflake/snowflake-pipelines-streams-tasks/&quot;&gt;pipeline architecture choices&lt;/a&gt;, this adds a new dimension to the build question.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-dcm-project-and-how-does-the-syntax-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dcm-projects-declarative-iac/#what-is-a-dcm-project-and-how-does-the-syntax-work&quot;&gt;&lt;span&gt;What is a DCM Project and how does the syntax work?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A DCM Project is a collection of SQL definition files that describe the desired state of your Snowflake objects. Instead of writing imperative CREATE OR ALTER statements and hoping they run in the right order, you write DEFINE statements that declare what an object should look like. Snowflake compares the declared state to the current state and computes the delta.&lt;/p&gt;
&lt;p&gt;The DEFINE keyword is the building block. A database and table definition based on the pattern documented in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dcm-projects/dcm-projects-overview&quot;&gt;Snowflake DCM overview&lt;/a&gt; looks like:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;DEFINE &lt;span class=&quot;token keyword&quot;&gt;DATABASE&lt;/span&gt; my_analytics
  &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;Analytics warehouse objects&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

DEFINE &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; my_analytics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reporting&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;daily_revenue &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  order_date &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  revenue NUMBER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  region &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&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;Daily revenue by region&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The real power comes from Jinja templating, which is built in. You can parameterize definitions for multiple environments:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;DEFINE &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reporting&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;daily_revenue &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  order_date &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  revenue NUMBER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  region &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&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;Daily revenue for &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Jinja, you pass variables like &lt;code&gt;env=staging&lt;/code&gt; at deploy time, so one project definition serves dev, staging, and production without duplicate files. Loops, conditions, and macros are all available, which means you can generate repetitive definitions (one table per region, one task per schema) without copy-paste sprawl.&lt;/p&gt;
&lt;p&gt;Project files live in three places: a &lt;strong&gt;Snowflake Workspace&lt;/strong&gt; managed inside Snowsight, a &lt;strong&gt;remote Git repository&lt;/strong&gt;, or a &lt;strong&gt;local directory&lt;/strong&gt;. You can manage them through Snowsight, the Snowflake CLI, SQL, or the Cortex Code CLI. That flexibility is deliberate: whether your team lives in the Snowflake UI or in a terminal, there is an entry point.&lt;/p&gt;
&lt;h2 id=&quot;how-does-the-plan-then-deploy-workflow-run&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dcm-projects-declarative-iac/#how-does-the-plan-then-deploy-workflow-run&quot;&gt;&lt;span&gt;How does the plan-then-deploy workflow run?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The core workflow is plan, review, deploy. You define the desired state, Snowflake generates a plan showing what will change, you review it, and then you execute. The command at the center is EXECUTE DCM PROJECT, which is generally available and documented in the &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/execute-dcm-project&quot;&gt;Snowflake SQL reference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A deploy from the Snowflake CLI:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;snow dcm execute &lt;span class=&quot;token parameter variable&quot;&gt;--project&lt;/span&gt; my_analytics &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--variable&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;production&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or via SQL:&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;EXECUTE&lt;/span&gt; DCM PROJECT my_analytics
  &lt;span class=&quot;token keyword&quot;&gt;USING&lt;/span&gt; VARIABLES &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;env &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;production&#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;One important nuance: the explicit &lt;strong&gt;PREVIEW and TEST commands are still in Preview&lt;/strong&gt; as of the GA release. The GA plan-then-deploy story relies on EXECUTE DCM PROJECT, which applies changes. If you want a dedicated dry-run verb before applying, that specific SQL command is not yet production-ready. Plan accordingly: test in a lower environment where EXECUTE is safe, and treat staging as your dry run until the PREVIEW command ships as GA.&lt;/p&gt;
&lt;p&gt;To monitor what DCM Projects have done in your account, query ACCOUNT_USAGE:&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;
  project_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  executed_by&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  executed_at
&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;DCM_PROJECT_EXECUTIONS
&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; executed_at &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;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This view is your audit trail. Every execution logs who ran it and when. Wire it into a dashboard or an alert so you catch unintended schema drift the moment it happens. The exact view columns depend on the ACCOUNT_USAGE schema Snowflake publishes, so verify the column names against your account&#39;s information schema before building dashboards on top of it.&lt;/p&gt;
&lt;h2 id=&quot;how-does-dcm-compare-to-terraform-and-raw-sql-scripts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dcm-projects-declarative-iac/#how-does-dcm-compare-to-terraform-and-raw-sql-scripts&quot;&gt;&lt;span&gt;How does DCM compare to Terraform and raw SQL scripts?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most teams deploying Snowflake objects today use one of two approaches. Terraform with the Snowflake provider gives you declarative state and a plan output, but it runs outside Snowflake and requires a state file you have to manage. Raw SQL scripts in CI/CD give you full control but no diff, no drift detection, and no idempotency without careful scripting. DCM Projects splits the difference.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;DCM Projects&lt;/th&gt;
&lt;th&gt;Terraform + provider&lt;/th&gt;
&lt;th&gt;Raw SQL scripts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where it runs&lt;/td&gt;
&lt;td&gt;Inside Snowflake&lt;/td&gt;
&lt;td&gt;External CI runner&lt;/td&gt;
&lt;td&gt;Any CI runner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State management&lt;/td&gt;
&lt;td&gt;Snowflake computes the diff&lt;/td&gt;
&lt;td&gt;Terraform state file&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plan or dry run&lt;/td&gt;
&lt;td&gt;EXECUTE DCM PROJECT (GA); PREVIEW command (Preview)&lt;/td&gt;
&lt;td&gt;terraform plan (GA)&lt;/td&gt;
&lt;td&gt;None without custom code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jinja templating&lt;/td&gt;
&lt;td&gt;Built in&lt;/td&gt;
&lt;td&gt;HCL variables and for_each&lt;/td&gt;
&lt;td&gt;Requires external templating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object coverage&lt;/td&gt;
&lt;td&gt;Broad, but pipes and streams in Preview&lt;/td&gt;
&lt;td&gt;Broad via provider&lt;/td&gt;
&lt;td&gt;Anything you script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lock-in&lt;/td&gt;
&lt;td&gt;Snowflake-only definitions&lt;/td&gt;
&lt;td&gt;Portable HCL, provider-dependent&lt;/td&gt;
&lt;td&gt;Fully portable SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drift detection&lt;/td&gt;
&lt;td&gt;Snowflake checks current vs desired on execute&lt;/td&gt;
&lt;td&gt;terraform plan detects drift&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The trade-off is clear. DCM Projects removes the need for an external runner and a state file, which simplifies CI/CD and cuts the number of moving parts. But it locks your deployment definitions to Snowflake. If your infrastructure spans AWS, dbt, and Snowflake, Terraform still has a role for the parts outside Snowflake. If Snowflake is your whole world, DCM is the simpler path.&lt;/p&gt;
&lt;h2 id=&quot;what-does-it-cost-and-what-edition-do-you-need&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dcm-projects-declarative-iac/#what-does-it-cost-and-what-edition-do-you-need&quot;&gt;&lt;span&gt;What does it cost and what edition do you need?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the good news for anyone who owns the Snowflake bill: &lt;strong&gt;DCM Projects does not introduce a separate credit charge&lt;/strong&gt;. The feature runs within your existing Snowflake account. The compute used for planning and applying changes runs on a warehouse, so the cost is the warehouse compute you are already paying for. There is no per-execution fee, no marketplace listing, and no premium edition requirement called out in the GA announcement.&lt;/p&gt;
&lt;p&gt;Check whether the feature is visible in your account:&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; FUNCTIONS &lt;span class=&quot;token operator&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;EXECUTE%DCM%&#39;&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 command resolves, DCM Projects is available. If not, check with your account admin or Snowflake support, as feature rollout can lag the release-note date by days.&lt;/p&gt;
&lt;p&gt;The real cost is the time to migrate. If you have hundreds of Terraform resources or thousands of lines of imperative SQL, converting them to DEFINE statements is a project, not an afternoon. Start with one schema or one pipeline, prove the workflow, and expand from there.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-dcm-projects-declarative-iac-fig-cap-status.png&quot; alt=&quot;Bar chart showing Snowflake DCM Projects capability split at GA: 7 capabilities generally available and 8 capabilities still in Preview, as of August 7 2026&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: Snowflake DCM Projects capability count at GA on August 7 2026. 7 capabilities generally available (declarative definitions, Jinja templating, plan-then-deploy, broad object support, pipeline management, management interfaces, storage options). 8 capabilities still in Preview (TEST/PREVIEW commands, GitHub Actions, DEFINE PIPE, DEFINE STREAM, DEFINE MASKING POLICY, DEFINE ROW ACCESS POLICY, ATTACH TAG, inherited grants). Source: Snowflake release notes.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The chart above shows the capability split at GA. &lt;strong&gt;7 capabilities are generally available&lt;/strong&gt;, including the DEFINE statement core, Jinja templating, and the plan-then-deploy workflow. &lt;strong&gt;8 capabilities remain in Preview&lt;/strong&gt;, and several of them are the governance and pipeline objects you most need for production.&lt;/p&gt;
&lt;h2 id=&quot;what-is-still-in-preview-and-what-should-you-avoid&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dcm-projects-declarative-iac/#what-is-still-in-preview-and-what-should-you-avoid&quot;&gt;&lt;span&gt;What is still in Preview and what should you avoid?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The GA is real, but it is not complete. These capabilities remain in Preview:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TEST and PREVIEW commands&lt;/strong&gt;: the dry-run verbs are not GA yet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Actions for DCM Projects&lt;/strong&gt;: no native CI integration yet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DEFINE PIPE&lt;/strong&gt;: cannot declaratively manage Snowpipe objects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DEFINE STREAM&lt;/strong&gt;: cannot declaratively manage streams&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DEFINE MASKING POLICY&lt;/strong&gt;: cannot declaratively manage masking policies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DEFINE ROW ACCESS POLICY&lt;/strong&gt;: cannot declaratively manage row access policies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ATTACH TAG&lt;/strong&gt;: cannot declaratively attach tags to objects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inherited grants and container-level MANAGE GRANTS&lt;/strong&gt;: advanced grant patterns not supported&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your governance story depends on masking policies, row access policies, or tag-based protections, DCM Projects cannot manage those objects declaratively today. You will still need imperative SQL or Terraform for that layer. For a deeper look at those governance objects, see our guide on &lt;a href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/&quot;&gt;Snowflake RBAC and masking&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Similarly, if your pipeline uses streams, you are out of luck for declarative management. You can declaratively define dynamic tables and tasks, but streams remain imperative. For teams building event-driven pipelines, this is the gap to watch.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-pragmatic-migration-path&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dcm-projects-declarative-iac/#what-is-the-pragmatic-migration-path&quot;&gt;&lt;span&gt;What is the pragmatic migration path?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start with objects that are fully GA: databases, tables, tasks, and dynamic tables. These cover the bulk of what most teams deploy repeatedly. Leave pipes, streams, and governance policies in your existing tooling for now.&lt;/p&gt;
&lt;p&gt;A practical sequence:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pick one non-production schema with a handful of tables and a task&lt;/li&gt;
&lt;li&gt;Write DEFINE statements for those objects in a local directory or Git repo&lt;/li&gt;
&lt;li&gt;Run EXECUTE DCM PROJECT against a dev database&lt;/li&gt;
&lt;li&gt;Verify the objects match, then tear them down and re-execute to confirm idempotency&lt;/li&gt;
&lt;li&gt;Wire the Snowflake CLI into your CI pipeline with a shell step&lt;/li&gt;
&lt;li&gt;Expand schema by schema, checking the execution history after each run&lt;/li&gt;
&lt;li&gt;Move the project storage to a remote Git repository once the workflow is stable&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The GRANT that controls who can execute DCM Projects:&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;EXECUTE&lt;/span&gt; MANAGE DCM PROJECT &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 dcm_deployer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restrict this to a dedicated deployment role. DCM Projects can create, alter, and drop objects, so the execute privilege is powerful. Do not grant it broadly, and do not let your CI service role carry it into production without a gate.&lt;/p&gt;
&lt;p&gt;A before-and-after for a simple table change shows the value. Before DCM, adding a column meant writing an ALTER TABLE script, versioning it, running it in each environment, and hoping nobody ran it twice. With DCM, you change the DEFINE TABLE block, run EXECUTE DCM PROJECT, and Snowflake applies only the column addition:&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;-- Before: imperative, order-dependent&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; reporting&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;daily_revenue &lt;span class=&quot;token keyword&quot;&gt;ADD&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;COLUMN&lt;/span&gt; currency &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- After: declarative, idempotent&lt;/span&gt;
DEFINE &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; reporting&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;daily_revenue &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  order_date &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  revenue NUMBER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  region &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  currency &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&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;Daily revenue by region&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run it once, run it a hundred times. The result is the same.&lt;/p&gt;
&lt;h2 id=&quot;the-bottom-line-for-your-deployment-pipeline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dcm-projects-declarative-iac/#the-bottom-line-for-your-deployment-pipeline&quot;&gt;&lt;span&gt;The bottom line for your deployment pipeline&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DCM Projects GA is a genuine step forward for Snowflake-native DevOps. It removes the external state file and the separate IaC runner for the objects it covers, and it does so without a new line item on your bill. The gaps are real but bounded: governance objects and streams will come, and until they do, you run a hybrid stack. If you are starting a new Snowflake project today, begin with DCM definitions. If you are running a mature Terraform setup, do not rip it out, but start migrating the object types DCM supports and shrink your Terraform footprint over time.&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-dcm-projects-declarative-iac/#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/release-notes/2026/other/2026-08-07-dcm-projects-ga&quot;&gt;Snowflake Release Notes: DCM Projects GA, August 7 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dcm-projects/dcm-projects-overview&quot;&gt;Snowflake DCM Projects Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dcm-projects/dcm-projects-use&quot;&gt;Snowflake DCM Projects Usage Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/execute-dcm-project&quot;&gt;EXECUTE DCM PROJECT SQL Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/developer-guide/builders/devops-with-snowflake&quot;&gt;DevOps with Snowflake Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Cortex AI Gateway: Snowflake&#39;s agent governance layer</title>
    <link href="https://data-today.net/snowflake/snowflake-cortex-ai-gateway/" />
    <updated>2026-08-03T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-cortex-ai-gateway/</id>
    <content type="html">&lt;p&gt;Your AI agents are about to have more access to your enterprise data than most of your engineers. Snowflake knows this, and at Black Hat 2026 the company shipped a control plane to do something about it. &lt;strong&gt;Cortex AI Gateway&lt;/strong&gt; is a centralized governance layer that sits between AI agents and the models, data, MCP servers, and tools those agents want to touch. It supports &lt;strong&gt;more than 100 MCP servers&lt;/strong&gt; and governs both Snowflake-native agents like CoCo and CoWork and third-party tools like Claude Code, Cursor, Amazon Bedrock, and custom LangChain apps. The catch: the gateway itself is heading to public preview soon, and most of its marquee features, including cost control, intelligent model routing, and observability, are still in private preview.&lt;/p&gt;
&lt;p&gt;The timing is not accidental. AI security concerns surged from &lt;strong&gt;17 percent of organizations in 2024 to 48 percent in 2026&lt;/strong&gt;, according to The Linux Foundation&#39;s 2026 State of Tech Talent Report, &lt;a href=&quot;https://www.snowflake.com/en/blog/enterprise-ai-security-agentic-mcp-governance/&quot;&gt;as cited by Snowflake&lt;/a&gt;. Meanwhile 97 percent of organizations say they are committed to implementing AI, and 57 percent face a significant capacity gap in security and risk management. The gap between adoption and security is where data exfiltration, tool hijacking, and runaway token costs live.&lt;/p&gt;
&lt;p&gt;If you own a Snowflake bill or govern data access in a Snowflake environment, this is the feature set that determines whether you let agents into production or keep them in sandboxes. Here is what shipped, what is real, and what you should do about it.&lt;/p&gt;
&lt;h2 id=&quot;what-shipped-at-black-hat-2026-and-what-is-still-private-preview&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-gateway/#what-shipped-at-black-hat-2026-and-what-is-still-private-preview&quot;&gt;&lt;span&gt;What shipped at Black Hat 2026 and what is still private preview?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake announced a bundle of features, but they are not all at the same maturity. Sorting them by availability tells you what you can put in a production architecture today versus what is still a roadmap promise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generally available now:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Agent Identity&lt;/strong&gt;: Security and governance teams can enforce data access policies that apply specifically when an agent is in the session, even if the agent runs on behalf of a privileged user. Snowflake added dedicated agent identity tracking in ACCOUNT_USAGE views for auditing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Native AI Security Posture Management&lt;/strong&gt;: Integrated into the Trust Center, this gives security operations a dashboard to scan for AI-specific configuration risks, assess compliance against emerging regulations, and deploy programmatic remediations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data movement policies&lt;/strong&gt;: Strict policies that govern where data can move, now GA, pairing with the preview DXP package for enforcement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ransomware Protection via Multi-Party Approval&lt;/strong&gt;: Requires &lt;strong&gt;two or more authorizations&lt;/strong&gt; before any destructive system change can proceed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;In preview or coming soon:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cortex AI Gateway&lt;/strong&gt;: Public preview soon. The overall gateway for agent access, cost, and audit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Exfiltration Prevention (DXP)&lt;/strong&gt;: Preview, via the Trust Center.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restricted Session Scope&lt;/strong&gt;: GA soon. Limits agent sessions to only what a task requires.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Private preview (request access, no public docs):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Wide Model Catalog, Access Governance and Sprawl Control, Govern Every Agent Connection, Observability and Tracing, Agent Action Auditability, AI Cost Control, Intelligent Model Routing, Context-Aware Access Policies, and CoCo CLI VM Sandbox.&lt;/p&gt;
&lt;p&gt;The chart below shows the breakdown: &lt;strong&gt;4 features are GA, 3 are in some preview stage, and 9 are in private preview&lt;/strong&gt;. If you are planning an architecture around this, most of the value is still behind a door you have to knock on.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-cortex-ai-gateway-fig-feature-status.png&quot; alt=&quot;Bar chart showing 4 features generally available, 3 features in preview, and 9 features in private preview for Cortex AI Gateway&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Cortex AI Gateway feature availability: 4 GA, 3 preview, 9 private preview. Source: Snowflake blog, Data Today analysis.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;how-does-the-gateway-govern-mcp-server-access&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-gateway/#how-does-the-gateway-govern-mcp-server-access&quot;&gt;&lt;span&gt;How does the gateway govern MCP server access?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MCP, the Model Context Protocol, has become the standard for connecting LLMs to databases, internal tools, and SaaS environments. The problem is that every team that adopts MCP does it differently, with no central visibility. Snowflake&#39;s answer is to put a gateway in front of all of it.&lt;/p&gt;
&lt;p&gt;Cortex AI Gateway integrates Natoma, the MCP gateway company Snowflake &lt;a href=&quot;https://venturebeat.com/security/snowflake-launches-cortex-ai-gateway-to-control-ai-agents-and-prevent-runaway-enterprise-costs&quot;&gt;acquired in May 2026&lt;/a&gt;, directly into the platform. Natoma enforced identity, policy, and audit at the tool-call level. Now that enforcement lives inside Snowflake&#39;s governance framework.&lt;/p&gt;
&lt;p&gt;The gateway sits between agents and the things they want to reach. An agent, whether it is CoCo running inside Snowflake or Claude Code running on a developer laptop, makes a request to call a tool or access a model. The gateway checks three things: who requested the action, what permissions they have, and whether the action is allowed. If the answer is yes, the call proceeds and is logged. If no, the call is blocked.&lt;/p&gt;
&lt;p&gt;For first-party agents, this is native. For third-party agents, Snowflake announced integrations with &lt;strong&gt;1Password, Aembit, Cyera, Linx Security, Okta, SailPoint, and Saviynt&lt;/strong&gt; to extend the same identity framework outward. A governance policy you write for a Snowflake-native agent also covers a Claude Code session hitting your data.&lt;/p&gt;
&lt;p&gt;The access control model uses Snowflake&#39;s standard privilege framework. A simplified grant for gateway-managed tool access:&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;-- Grant a role access to a gateway-managed MCP integration&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- (exact object type will be documented at public preview)&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; INTEGRATION my_mcp_integration
    &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE agent_operator_role&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- Grant access to Cortex AI functions (standard Snowflake pattern)&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; SNOWFLAKE &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE agent_operator_role&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; SNOWFLAKE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CORTEX &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE agent_operator_role&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The exact privilege names and object types for the gateway are not yet publicly documented since the feature is in preview. What you should take away is that agent access will be governed by roles and grants you control, not by API keys scattered across developer machines.&lt;/p&gt;
&lt;h2 id=&quot;what-can-you-actually-enforce-with-agent-identity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-gateway/#what-can-you-actually-enforce-with-agent-identity&quot;&gt;&lt;span&gt;What can you actually enforce with agent identity?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Agent Identity is GA, and it is the feature you can use today. The core idea: when an agent is in a session, Snowflake knows it is an agent, not a human user, and can enforce policies accordingly.&lt;/p&gt;
&lt;p&gt;This matters because agents often run under privileged roles. A data scientist with SYSADMIN privileges kicks off an agent to analyze a table. Without agent identity, that agent has the full power of the role. With agent identity, you can write policies that restrict access to sensitive columns, block DDL, or limit the session to read-only when an agent is the actor.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Without Agent Identity&lt;/th&gt;
&lt;th&gt;With Agent Identity (GA)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent runs under SYSADMIN&lt;/td&gt;
&lt;td&gt;Full admin access to all objects&lt;/td&gt;
&lt;td&gt;Policies restrict agent to task scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auditing who did what&lt;/td&gt;
&lt;td&gt;Query shows the human user&lt;/td&gt;
&lt;td&gt;Query shows agent identity and human user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sensitive column access&lt;/td&gt;
&lt;td&gt;Agent sees everything the role allows&lt;/td&gt;
&lt;td&gt;Masking policies can trigger on agent context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Destructive actions&lt;/td&gt;
&lt;td&gt;Agent can drop tables if role allows&lt;/td&gt;
&lt;td&gt;Restricted Session Scope (GA soon) blocks this&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;You can audit agent activity through ACCOUNT_USAGE views. A query to find agent-driven access to sensitive tables:&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;-- Identify queries executed in the last 24 hours&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- Agent identity columns are new in GA; filter for agent sessions&lt;/span&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;
    query_text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    user_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    role_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    start_time&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    execution_status
&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;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 operator&quot;&gt;AND&lt;/span&gt; query_type &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;SELECT&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;INSERT&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;UPDATE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;DELETE&#39;&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 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;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Agent Identity GA, Snowflake has added agent-specific tracking to these views. The exact column names depend on your Snowflake version, but the capability means you can filter for queries where an agent was the actor, not just the human who started the session. This is the audit trail your security team needs when someone asks which agent touched the customer table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Restricted Session Scope&lt;/strong&gt; is the companion feature, marked GA soon. It limits what an agent session can do to only what the task requires. A read-only analysis stays read-only, even if the user&#39;s role normally allows INSERT or DELETE. This is the principle of least privilege applied to agent sessions, and it is the feature that makes running agents under privileged roles defensible.&lt;/p&gt;
&lt;h2 id=&quot;how-does-the-cost-control-layer-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-gateway/#how-does-the-cost-control-layer-work&quot;&gt;&lt;span&gt;How does the cost control layer work?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the section that matters if you own the bill. AI Cost Control, in private preview, gives you a unified view of AI consumption by team, agent, or workload. You can set budget guardrails and route requests to cheaper models for simpler tasks.&lt;/p&gt;
&lt;p&gt;Intelligent Model Routing, also private preview, automatically routes agent requests to the right model based on cost, latency, capability, and data residency. If a simple summarization task does not need the most expensive model, the gateway can route it to a cheaper one. If a task requires reasoning, it goes to the stronger model. The gateway also enforces data residency: requests stay in the region they need to stay in.&lt;/p&gt;
&lt;p&gt;The cost model for the gateway itself is not yet published. Snowflake has not announced specific credit pricing for Cortex AI Gateway in the source material. What is clear is that the feature is designed to control AI consumption costs: the token spend across external model providers like OpenAI, Anthropic, and Google, not the Snowflake compute credits you already track. If your team is spending on external model APIs through Snowflake, the gateway is the layer that puts guardrails around that spend.&lt;/p&gt;
&lt;p&gt;For a parallel on how Snowflake thinks about cost control, see our guide on &lt;a href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-costs/&quot;&gt;Snowflake Adaptive Compute costs&lt;/a&gt;. The same philosophy of applying guardrails before the bill runs away now extends to AI token consumption.&lt;/p&gt;
&lt;p&gt;What you would do: if you are in the private preview, set per-agent budget caps immediately. If you are not, start instrumenting your current agent workloads with ACCOUNT_USAGE queries to establish a baseline of what agents are actually costing you today.&lt;/p&gt;
&lt;h2 id=&quot;what-does-data-exfiltration-prevention-actually-block&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-gateway/#what-does-data-exfiltration-prevention-actually-block&quot;&gt;&lt;span&gt;What does data exfiltration prevention actually block?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Data Exfiltration Prevention (DXP) package is in preview via the Trust Center. It pairs real-time telemetry with the now-GA data movement policies to detect and intercept unauthorized data flows before they exit the ecosystem.&lt;/p&gt;
&lt;p&gt;The platform can proactively flag and block three specific patterns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sensitive data fetches triggered by AI agents&lt;/strong&gt;: An agent queries a table with PII or financial data, and the system flags or blocks the retrieval based on policy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unauthorized data routing to internal or external stages&lt;/strong&gt;: Data moves to a storage location that is not approved, and the movement is intercepted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mass data downloads via user interfaces&lt;/strong&gt;: A user or agent attempts to export a large volume of data through the UI, and the download is blocked.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The underlying data movement policies are GA, meaning you can author and enforce them now. The DXP package adds the real-time telemetry and detection layer on top. A basic network policy in Snowflake:&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 network policy to restrict allowed IP ranges&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; NETWORK POLICY corp_allowed_egress
    ALLOWED_IP_LIST &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 string&quot;&gt;&#39;10.0.0.0/8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&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;Restrict data movement to corporate network&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- Apply the network policy at the account level&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; ACCOUNT &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; NETWORK_POLICY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; corp_allowed_egress&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is not a new concept if you already use Snowflake network policies. What is new is the pairing with AI-specific telemetry: the system can distinguish between a human user downloading a CSV and an agent triggering a bulk data fetch, and apply different rules to each.&lt;/p&gt;
&lt;h2 id=&quot;should-you-build-on-this-today-or-wait&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-gateway/#should-you-build-on-this-today-or-wait&quot;&gt;&lt;span&gt;Should you build on this today or wait?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the honest read. If you are deciding whether to architect around Cortex AI Gateway right now, the answer depends on what you need.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build on what is GA today:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agent Identity for auditing and policy enforcement on agent sessions.&lt;/li&gt;
&lt;li&gt;AI Security Posture Management in the Trust Center for scanning configuration risks.&lt;/li&gt;
&lt;li&gt;Data movement policies for controlling where data goes.&lt;/li&gt;
&lt;li&gt;Multi-Party Approval for protecting destructive operations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Request private preview for:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The gateway itself, if you have MCP sprawl and need centralized access control across &lt;strong&gt;more than 100 MCP servers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;AI Cost Control, if your token spend is growing and you need budget guardrails.&lt;/li&gt;
&lt;li&gt;Intelligent Model Routing, if you are using multiple model providers and want automatic selection.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Wait on:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Context-Aware Access Policies (private preview) if you already have network policies and row access policies that work. The zero-trust evaluation of identity, network, and client context in a single expression is promising but unproven at scale.&lt;/li&gt;
&lt;li&gt;CoCo CLI VM Sandbox (private preview, macOS only) unless you have a specific need for kernel-level isolation of agent development environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The lock-in question is real. Cortex AI Gateway is built on Natoma, which Snowflake acquired. If you build your agent governance around this gateway, you are building around Snowflake&#39;s control plane. For organizations already deep in Snowflake, that is a reasonable trade. For teams running multi-cloud or multi-platform agent architectures, the gateway covers a wide catalog of MCP servers but the governance model is Snowflake-centric.&lt;/p&gt;
&lt;p&gt;If you want to start with something concrete, our guide to &lt;a href=&quot;https://data-today.net/snowflake/snowflake-cortex-agents/&quot;&gt;building an AI agent on your Snowflake data with Cortex Agents&lt;/a&gt; covers the agent side. Pair that with Agent Identity (GA) and data movement policies (GA), and you have a defensible production architecture for agent access today, even without the full gateway.&lt;/p&gt;
&lt;h2 id=&quot;the-trust-boundary-moved-inside-snowflake&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-cortex-ai-gateway/#the-trust-boundary-moved-inside-snowflake&quot;&gt;&lt;span&gt;The trust boundary moved inside Snowflake&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The important shift here is architectural. Agent governance used to be an application-layer problem: you built guardrails into your LangChain app, your MCP client, or your agent framework. &lt;a href=&quot;https://siliconangle.com/2026/07/28/snowflake-debuts-cortex-ai-gateway-govern-monitor-enterprise-ai-agents/&quot;&gt;Snowflake is arguing&lt;/a&gt; that security belongs in the data and control planes rather than bolted onto the application. Cortex AI Gateway, Agent Identity, and DXP move the trust boundary inside Snowflake itself.&lt;/p&gt;
&lt;p&gt;That argument is sound if your data lives in Snowflake. The features that are GA today, Agent Identity and data movement policies, are enough to start governing agent access in production. The features that are still in private preview, cost control, model routing, and observability, are the ones that will make the gateway worth the architectural commitment. Watch for the public preview transition. That is when you will know whether the gateway delivers on the promise or stays a roadmap item.&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-gateway/#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://www.snowflake.com/en/blog/enterprise-ai-security-agentic-mcp-governance/&quot;&gt;Snowflake Blog&lt;/a&gt; - Enterprise AI Security: Agentic Controls and MCP Governance&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://venturebeat.com/security/snowflake-launches-cortex-ai-gateway-to-control-ai-agents-and-prevent-runaway-enterprise-costs&quot;&gt;VentureBeat&lt;/a&gt; - Snowflake launches Cortex AI Gateway to control AI agents and prevent runaway enterprise costs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://siliconangle.com/2026/07/28/snowflake-debuts-cortex-ai-gateway-govern-monitor-enterprise-ai-agents/&quot;&gt;SiliconANGLE&lt;/a&gt; - Snowflake debuts Cortex AI Gateway to govern and monitor enterprise AI agents&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://finance.yahoo.com/technology/ai/articles/snowflake-advances-trusted-agentic-enterprise-130100029.html&quot;&gt;Yahoo Finance / Business Wire&lt;/a&gt; - Snowflake Advances the Trusted Agentic Enterprise Era with Unified Monitoring and Cost Management&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake tag-based data protection policies: a governance shift</title>
    <link href="https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/" />
    <updated>2026-07-27T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/</id>
    <content type="html">&lt;p&gt;Snowflake just made it possible to attach a data protection policy to a tag, and have every object carrying that tag inherit the policy automatically. Tag-based data protection policies entered public preview on July 21, 2026, covering four policy types: row access, aggregation, projection, and join policies. The shift is from object-by-object governance to attribute-based access control (ABAC), where a single tag assignment can lock down a column, a table, or an entire schema without writing a separate &lt;code&gt;ALTER TABLE ... SET POLICY&lt;/code&gt; for each one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The core mechanic: one tag, one policy, automatic propagation.&lt;/strong&gt; You create a tag, set a policy on the tag, then set the tag on any object. The object inherits the policy through Snowflake&#39;s existing tag propagation rules. Add a new table and tag it, and the policy is already enforced. This is a concrete decision for any team managing access control at scale on Snowflake, and it pairs naturally with the fundamentals covered in our &lt;a href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/&quot;&gt;Snowflake RBAC and masking guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-exactly-shipped-in-this-release&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/#what-exactly-shipped-in-this-release&quot;&gt;&lt;span&gt;What exactly shipped in this release?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake &lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-07-21-tag-based-policies-preview&quot;&gt;announced tag-based policy support&lt;/a&gt; as a public preview feature on July 21, 2026. It covers four policy types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Row access policies&lt;/strong&gt;: filter rows based on the querying role or context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Aggregation policies&lt;/strong&gt;: enforce minimum group sizes, suppressing small aggregates to prevent inference attacks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Projection policies&lt;/strong&gt;: restrict which columns a role can project, complementing column-level masking.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Join policies&lt;/strong&gt;: control which tables can be joined together, preventing cross-domain data leakage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tag-based-policies&quot;&gt;general workflow&lt;/a&gt; for all four types follows the same three steps. First, create a tag. Second, set the policy on the tag with an &lt;code&gt;ALTER TAG&lt;/code&gt; command. Third, set the tag on the object. The object then inherits the policy automatically.&lt;/p&gt;
&lt;p&gt;Here is the DDL for creating a tag and attaching a row access policy:&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;-- Step 1: create the tag&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; TAG &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXISTS&lt;/span&gt; governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pii_sensitive
  &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;Marks objects subject to PII row-level controls&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- Step 2: set a row access policy on the tag&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; TAG governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pii_sensitive
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; ACCESS POLICY governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pii_row_filter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- Step 3: set the tag on a table&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; sales&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customers
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; TAG governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pii_sensitive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;true&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The table now enforces &lt;code&gt;governance.pii_row_filter&lt;/code&gt; for any query against it, with no direct &lt;code&gt;ALTER TABLE ... SET ROW ACCESS POLICY&lt;/code&gt; call. The same pattern works for the other three policy types, each with its own &lt;code&gt;ALTER TAG&lt;/code&gt; variant.&lt;/p&gt;
&lt;p&gt;For aggregation policies, the syntax includes an optional &lt;code&gt;ENTITY KEY&lt;/code&gt; clause that specifies the grouping columns the policy applies to:&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; TAG governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;aggregate_sensitive
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; AGGREGATION POLICY governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;min_group_size_5
  ENTITY &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;department_id&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 &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tag-based-aggregation-policies&quot;&gt;tag-based aggregation policy documentation&lt;/a&gt; confirms that smaller groups are suppressed when the aggregate query produces results below the policy&#39;s minimum threshold. The entity key tells the policy which columns define the group boundary.&lt;/p&gt;
&lt;p&gt;For projection policies, the pattern is the same:&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; TAG governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;restricted_columns
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; PROJECTION POLICY governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;limit_projection&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;how-does-tag-inheritance-propagate-the-policy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/#how-does-tag-inheritance-propagate-the-policy&quot;&gt;&lt;span&gt;How does tag inheritance propagate the policy?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where the feature earns its keep. Snowflake tags already support &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tag-based-policies&quot;&gt;inheritance and propagation&lt;/a&gt; across the object hierarchy. When you set a tag on a database or schema, every table and view inside inherits that tag. Now that policies can ride on tags, the inheritance carries the policy with it.&lt;/p&gt;
&lt;p&gt;The inheritance chain works like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Object level&lt;/th&gt;
&lt;th&gt;Tag set here&lt;/th&gt;
&lt;th&gt;Policy applies to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ALTER DATABASE db SET TAG pii = &#39;true&#39;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All schemas, tables, views in the database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schema&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ALTER SCHEMA sch SET TAG pii = &#39;true&#39;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All tables and views in the schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Table&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ALTER TABLE tbl SET TAG pii = &#39;true&#39;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All columns and the table itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;View&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ALTER VIEW vw SET TAG pii = &#39;true&#39;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The view, queried through the policy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The key behavior: if a tag is set at the database level, every new table created in that database inherits the tag and the policy. &lt;strong&gt;You do not need to touch the new table at all.&lt;/strong&gt; This is the operational win. A data engineer creating a derived table from a tagged source does not need to remember to attach the policy. The tag does the remembering.&lt;/p&gt;
&lt;p&gt;There is a subtlety. Tag propagation is not the same as policy cascading. The tag propagates, and the policy is attached to the tag, so the effective policy on any object is the one bound to the most specific tag that applies. If a table has a tag set directly and the schema has the same tag set, the table-level tag wins. If different tags with different policies are set at different levels, you need to understand the precedence rules.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-migrate-from-per-object-policies-to-tag-based-policies&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/#how-do-you-migrate-from-per-object-policies-to-tag-based-policies&quot;&gt;&lt;span&gt;How do you migrate from per-object policies to tag-based policies?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you already have row access or projection policies attached directly to dozens of tables, you can migrate to the tag-based model. The process is straightforward but requires care.&lt;/p&gt;
&lt;p&gt;First, inventory what you have. This ACCOUNT_USAGE query finds every object with a row access policy attached directly:&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;
  policy_db&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  policy_schema&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  policy_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ref_database_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ref_schema_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ref_entity_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ref_entity_domain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  tag
&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;policy_references
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; policy_kind &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ROW_ACCESS_POLICY&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; tag &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;-- direct attachment, not tag-based&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; ref_database_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ref_schema_name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;tag&lt;/code&gt; column in &lt;code&gt;POLICY_REFERENCES&lt;/code&gt; is NULL for direct attachments and non-NULL when the policy comes through a tag. This is how you audit the transition.&lt;/p&gt;
&lt;p&gt;Second, create a tag for each logical policy group. If you have a row access policy called &lt;code&gt;sales_region_filter&lt;/code&gt; attached to 30 tables, create a tag called &lt;code&gt;region_filtered&lt;/code&gt; and set the policy on it:&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; TAG governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region_filtered&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; TAG governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region_filtered
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; ACCESS POLICY governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sales_region_filter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Third, set the tag on the objects and drop the direct policy attachment:&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;-- set the tag&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; sales&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;east_region &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; TAG governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region_filtered &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;true&#39;&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; sales&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;west_region &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; TAG governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region_filtered &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;true&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- drop the direct policy attachment&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; sales&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;east_region
  UNSET &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; ACCESS POLICY governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sales_region_filter&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; sales&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;west_region
  UNSET &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; ACCESS POLICY governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sales_region_filter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do this in batches and verify with the ACCOUNT_USAGE query after each batch. The policy enforcement does not interrupt during the migration: the direct policy is active until you unset it, and the tag-based policy is active as soon as the tag is set. There is a brief window where both are active, but since they are the same policy, the behavior is identical.&lt;/p&gt;
&lt;h2 id=&quot;what-does-this-cost-in-credits-and-complexity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/#what-does-this-cost-in-credits-and-complexity&quot;&gt;&lt;span&gt;What does this cost in credits and complexity?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Tag-based policies do not introduce new credit charges. &lt;strong&gt;The compute cost is the same as per-object policies.&lt;/strong&gt; Row access policies, aggregation policies, and projection policies all execute during query runtime, and that runtime cost has not changed. What changes is the management overhead.&lt;/p&gt;
&lt;p&gt;The chart below illustrates the operational difference for a 400-object estate where each object needs a row access policy:&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-tag-based-data-protection-policies-fig-fig-scale.png&quot; alt=&quot;Bar chart comparing per-object policy management versus tag-based policy management across four dimensions. Per-object: 1,200 policy attachments for 400 objects, 3 hours for audit queries, high risk of drift, no auto-inheritance. Tag-based: 1 policy attachment per tag, 15 minutes for audit queries, low risk of drift, automatic inheritance on tag assignment.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: per-object vs tag-based policy management for a 400-object estate. Synthetic example based on Snowflake documentation patterns. Data Today benchmark.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;In the per-object model, you maintain &lt;strong&gt;1,200 policy attachments&lt;/strong&gt; (400 objects, each with up to three policy types). In the tag-based model, you maintain one tag per logical policy group and set tags on objects. The audit query time drops from roughly three hours of manual reconciliation to a 15-minute automated query against &lt;code&gt;POLICY_REFERENCES&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But tag-based policies introduce their own complexity costs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tag sprawl&lt;/strong&gt;: if you create a tag for every policy variant, you end up with dozens of tags that are hard to name, govern, and audit. Tags need a naming convention and a lifecycle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Policy precedence&lt;/strong&gt;: when multiple tags with different policies apply to the same object, the resolution order matters. You need to test and document which policy wins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit complexity&lt;/strong&gt;: the &lt;code&gt;POLICY_REFERENCES&lt;/code&gt; view now has two entry types (direct and tag-based). Auditors need to understand the difference and query both.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privilege separation&lt;/strong&gt;: the ability to set tags and the ability to create policies should be separated. A role that can both create a policy and attach it to a tag is a governance bypass.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The privilege model uses existing Snowflake tag privileges. To create and manage tags, a role needs the &lt;code&gt;CREATE TAG&lt;/code&gt; privilege on the schema. To set a policy on a tag, the role needs &lt;code&gt;APPLY ROW ACCESS POLICY&lt;/code&gt; (or the equivalent for other policy types) plus &lt;code&gt;APPLY TAG&lt;/code&gt; on the tag. To set a tag on an object, the role needs &lt;code&gt;APPLY TAG&lt;/code&gt; on the tag and ownership of the object.&lt;/p&gt;
&lt;p&gt;Here is the grant set for a governance 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 comment&quot;&gt;-- governance role can create tags and set policies on them&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; TAG &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SCHEMA&lt;/span&gt; governance &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE governance_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;APPLY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; ACCESS POLICY &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 governance_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;APPLY&lt;/span&gt; AGGREGATION POLICY &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 governance_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;APPLY&lt;/span&gt; PROJECTION POLICY &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 governance_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- data engineering roles can set tags on objects they own&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;APPLY&lt;/span&gt; TAG &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; TAG governance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pii_sensitive &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE data_engineer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The separation matters. If &lt;code&gt;data_engineer&lt;/code&gt; can create tags and set policies on them, they can effectively bypass any governance control by creating a new tag with no policy. Keep tag creation and policy attachment in the governance role, and give data engineers only the &lt;code&gt;APPLY TAG&lt;/code&gt; grant for setting existing tags on their objects.&lt;/p&gt;
&lt;h2 id=&quot;when-is-tag-based-policy-the-wrong-choice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/#when-is-tag-based-policy-the-wrong-choice&quot;&gt;&lt;span&gt;When is tag-based policy the wrong choice?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Tag-based policies shine when you have a policy that applies to many objects with the same protection needs. They are the wrong choice in three scenarios.&lt;/p&gt;
&lt;p&gt;First, when each object needs a slightly different policy. Row access policies that filter by region, for example, might use a different region column name on different tables. The tag-based model attaches one policy to a tag, and the policy must work for every object carrying that tag. If &lt;code&gt;customers&lt;/code&gt; uses &lt;code&gt;cust_region&lt;/code&gt; and &lt;code&gt;orders&lt;/code&gt; uses &lt;code&gt;order_region&lt;/code&gt;, a single row access policy on a tag will not work without a mapping table or a consistent column convention. In that case, direct per-object policies are simpler.&lt;/p&gt;
&lt;p&gt;Second, when the policy is temporary or experimental. If you are testing a new aggregation policy on a single table for two weeks, attaching it directly is faster than creating a tag, setting the policy on the tag, setting the tag on the table, and then cleaning up all three when the test ends. The tag-based model adds two extra DDL steps. For one object, that is overhead with no payoff.&lt;/p&gt;
&lt;p&gt;Third, when you need precise per-object audit trails. Tag-based policies make it harder to answer the question &amp;quot;what policy is on this specific table right now?&amp;quot; because the answer is indirect: the table has a tag, the tag has a policy. You can query it, but it is one more join in your audit logic. For environments where regulators require a direct, per-object policy inventory, per-object attachment may be easier to evidence.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-audit-tag-based-policy-enforcement&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/#how-do-you-audit-tag-based-policy-enforcement&quot;&gt;&lt;span&gt;How do you audit tag-based policy enforcement?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;POLICY_REFERENCES&lt;/code&gt; view in ACCOUNT_USAGE is the primary audit surface. It now includes a &lt;code&gt;TAG&lt;/code&gt; column that is non-NULL when the policy is applied through a tag.&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;
  ref_database_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ref_schema_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ref_entity_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ref_entity_domain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  policy_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  policy_kind&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  tag  &lt;span class=&quot;token comment&quot;&gt;-- NULL = direct, non-NULL = tag-based&lt;/span&gt;
&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;policy_references
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; ref_database_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;SALES&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; policy_kind &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;ROW_ACCESS_POLICY&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;AGGREGATION_POLICY&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                      &lt;span class=&quot;token string&quot;&gt;&#39;PROJECTION_POLICY&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;JOIN_POLICY&#39;&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; ref_entity_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; policy_kind&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For real-time auditing (the ACCOUNT_USAGE view has latency), use the Information Schema equivalent:&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; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; sales&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;information_schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;policy_references
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; policy_kind &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ROW_ACCESS_POLICY&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Information Schema view is current as of the query time, while ACCOUNT_USAGE has a latency of up to a few hours. For compliance reports, use ACCOUNT_USAGE for history and Information Schema for point-in-time checks.&lt;/p&gt;
&lt;p&gt;A useful governance query finds objects that have a tag with a policy but also have a direct policy attached, which can cause unexpected precedence conflicts:&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;
  ref_entity_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ref_entity_domain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  policy_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  policy_kind&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  tag
&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;policy_references
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; tag &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; ref_entity_name &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 keyword&quot;&gt;SELECT&lt;/span&gt; inner_q&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ref_entity_name
    &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;policy_references inner_q
    &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; inner_q&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tag &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&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; ref_entity_name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This surfaces objects where both a tag-based and a direct policy exist. Clean those up during migration to avoid ambiguity.&lt;/p&gt;
&lt;h2 id=&quot;what-should-you-do-during-public-preview&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/#what-should-you-do-during-public-preview&quot;&gt;&lt;span&gt;What should you do during public preview?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Public preview means the feature is usable but not GA. Three things to keep in mind.&lt;/p&gt;
&lt;p&gt;First, preview features can change. The SQL syntax, the privilege model, and the inheritance behavior may shift before GA. If you build automation around tag-based policies now, wrap it in a layer that can absorb syntax changes. Use stored procedures or a governance tool rather than hardcoding DDL in pipelines.&lt;/p&gt;
&lt;p&gt;Second, test tag propagation in a non-production account first. Create a tag at the schema level, set a row access policy on it, and verify that a new table created in that schema inherits the policy. Then test edge cases: renaming a table with a tag, dropping a tag that has a policy attached, and setting multiple tags with different policies on the same object.&lt;/p&gt;
&lt;p&gt;Third, start with one policy type. Row access policies are the most common and the easiest to validate. Attach one row access policy to one tag, set the tag on a small group of tables, and run your existing audit queries to confirm the behavior. Expand from there.&lt;/p&gt;
&lt;h2 id=&quot;the-governance-shortcut-you-still-have-to-earn&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-tag-based-data-protection-policies/#the-governance-shortcut-you-still-have-to-earn&quot;&gt;&lt;span&gt;The governance shortcut you still have to earn&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Tag-based policies solve the hardest part of data governance at scale: the fact that every new table is a potential gap. With tags, the policy travels with the classification, not the object. That is a real shift. But the tag still has to be set correctly, the policy still has to be written correctly, and the privilege model still has to separate the people who classify data from the people who create policies. The feature gives you the mechanism. The discipline is still yours.&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-tag-based-data-protection-policies/#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/release-notes/2026/other/2026-07-21-tag-based-policies-preview&quot;&gt;Snowflake Release Notes: Tag-based data protection policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tag-based-policies&quot;&gt;Snowflake Documentation: Tag-based policies overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tag-based-aggregation-policies&quot;&gt;Snowflake Documentation: Tag-based aggregation policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tag-based-row-access-policies&quot;&gt;Snowflake Documentation: Tag-based row access policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tag-based-projection-policies&quot;&gt;Snowflake Documentation: Tag-based projection policies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake workload identity federation kills static credentials</title>
    <link href="https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/" />
    <updated>2026-07-06T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/</id>
    <content type="html">&lt;p&gt;Every Snowflake pipeline that calls an external API has the same dirty secret: somewhere in a secret object, a UDF, or an integration, there is a long-lived credential that someone has to rotate. On July 1, 2026, Snowflake shipped workload identity federation for Snowflake workloads that access external services into general availability, and it removes that credential from the picture entirely. Snowflake now acts as the OpenID Connect provider, issuing &lt;strong&gt;short-lived ID tokens&lt;/strong&gt; that a Snowflake workload can present to an external service for authentication. No static key. No rotation calendar. No key accidentally expiring on a Friday night and breaking the pipeline. If you own the Snowflake bill or the security posture around it, this is the most consequential governance change of the quarter, and it costs you zero additional credits to use.&lt;/p&gt;
&lt;p&gt;The mechanics are straightforward. You create a secret of type &lt;code&gt;WORKLOAD_IDENTITY_FEDERATION&lt;/code&gt;, which makes Snowflake an OIDC provider with an issuer URL and registers the workload as an OIDC client with a subject identifier. You hand those two values to the external service so it can verify tokens. When the workload needs to authenticate, it calls &lt;code&gt;SYSTEM$ISSUE_WORKLOAD_IDENTITY_FEDERATION_TOKEN&lt;/code&gt;, receives an encoded ID token, and sends it to the service. The service verifies the token&#39;s signature against Snowflake&#39;s published public keys, checks the &lt;code&gt;iss&lt;/code&gt; and &lt;code&gt;sub&lt;/code&gt; and &lt;code&gt;aud&lt;/code&gt; claims, and grants access. The whole trust flow is four steps, shown in the chart below. The key number is zero: zero static credentials to rotate, zero additional compute cost, zero new integration objects to license.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-workload-identity-federation-guide-fig-wif-trust-flow.png&quot; alt=&quot;Workload identity federation trust flow across four steps. Snowflake creates secret and becomes OIDC provider at step 1. Admin shares issuer URL and subject with external service at step 2. Workload calls SYSTEM$ISSUE_WORKLOAD_IDENTITY_FEDERATION_TOKEN at step 3. External service verifies ID token signature and audience claim at step 4. Audience value is example-cloud-service.com.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: Four-step trust flow from secret creation through token issuance to external service verification. Issuer URL and subject identifier are shared with the external service to establish trust. Source: Snowflake documentation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;what-exactly-did-snowflake-ship&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/#what-exactly-did-snowflake-ship&quot;&gt;&lt;span&gt;What exactly did Snowflake ship?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake&#39;s release notes for July 1, 2026 confirm that workload identity federation for Snowflake workloads accessing external services is now generally available. The feature lets Snowflake act as the OIDC provider when a Snowflake workload authenticates to an external service, which is a role reversal worth pausing on. In most federation setups, the external service or a dedicated identity provider plays the OIDC provider role. Here, Snowflake itself holds that role, which means the trust anchor lives inside your Snowflake account and follows your account&#39;s replication and failover behaviour.&lt;/p&gt;
&lt;p&gt;The core objects and functions are minimal. A secret of type &lt;code&gt;WORKLOAD_IDENTITY_FEDERATION&lt;/code&gt; is a schema-level object that stores the issuer URL and subject identifier. The system function &lt;code&gt;SYSTEM$ISSUE_WORKLOAD_IDENTITY_FEDERATION_TOKEN&lt;/code&gt; takes two arguments: the secret identifier and a JSON payload specifying the audience, and returns an encoded ID token conforming to the OIDC specification. There is a &lt;strong&gt;1:1 relationship&lt;/strong&gt; between the Snowflake workload and Snowflake as the OIDC provider, but the same secret can authenticate to multiple services, which means you do not proliferate secrets for every downstream API.&lt;/p&gt;
&lt;p&gt;The DDL to create the secret is a single 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 keyword&quot;&gt;CREATE&lt;/span&gt; SECRET my_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;my_workload
  &lt;span class=&quot;token keyword&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; WORKLOAD_IDENTITY_FEDERATION&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the secret exists, you describe it to extract the two values the external service needs:&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;DESC&lt;/span&gt; SECRET my_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;my_workload&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output includes two columns you hand to the external service administrator: &lt;code&gt;workload_identity_federation_issuer&lt;/code&gt;, which is the issuer URL of Snowflake as the OIDC provider and maps to the &lt;code&gt;iss&lt;/code&gt; claim, and &lt;code&gt;workload_identity_federation_subject&lt;/code&gt;, which is the workload&#39;s OIDC client identifier and maps to the &lt;code&gt;sub&lt;/code&gt; claim. The external service compares those values against the incoming token. If they match, the token is authentic.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-issue-a-token-and-use-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/#how-do-you-issue-a-token-and-use-it&quot;&gt;&lt;span&gt;How do you issue a token and use it?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The token issuance function is callable from any context where a Snowflake workload runs: a stored procedure, a UDF, a Snowpark Container Services workload, or a task. The call takes the secret and an audience identifier in JSON format:&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; SYSTEM$ISSUE_WORKLOAD_IDENTITY_FEDERATION_TOKEN&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;my_db.auth.my_workload&#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;aud&quot;: &quot;example-cloud-service.com&quot;}&#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 audience value becomes the &lt;code&gt;aud&lt;/code&gt; claim of the returned ID token. You send that encoded token to the external service as a bearer credential. The service validates it by fetching Snowflake&#39;s public keys from the issuer URL&#39;s well-known endpoint, verifying the signature, and checking that the &lt;code&gt;iss&lt;/code&gt;, &lt;code&gt;sub&lt;/code&gt;, and &lt;code&gt;aud&lt;/code&gt; claims match what you pre-registered. This is standard OIDC token verification on the service side, so any service that already supports OIDC identity federation, such as GitHub Actions, Google Cloud Workload Identity Federation, or HashiCorp Vault, can be configured to trust Snowflake-issued tokens without custom code.&lt;/p&gt;
&lt;p&gt;A before-and-after makes the difference concrete:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Before (static credentials)&lt;/th&gt;
&lt;th&gt;After (workload identity federation)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Credential storage&lt;/td&gt;
&lt;td&gt;API key stored in a &lt;code&gt;PASSWORD&lt;/code&gt; or &lt;code&gt;OAUTH&lt;/code&gt; secret&lt;/td&gt;
&lt;td&gt;No stored credential. WIF secret holds issuer and subject only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotation&lt;/td&gt;
&lt;td&gt;Manual or scheduled rotation every 60 to 90 days&lt;/td&gt;
&lt;td&gt;No rotation. Tokens are short-lived and issued on demand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blast radius if leaked&lt;/td&gt;
&lt;td&gt;Static key works until revoked&lt;/td&gt;
&lt;td&gt;Stolen token expires within minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-service reuse&lt;/td&gt;
&lt;td&gt;One secret per service&lt;/td&gt;
&lt;td&gt;One WIF secret authenticates to multiple services via audience&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replication behaviour&lt;/td&gt;
&lt;td&gt;Secret replicates but external trust may break on failover&lt;/td&gt;
&lt;td&gt;Issuer and subject replicate unchanged. Trust survives failover&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-workload-identity-federation-guide-fig-wif-model-compare.png&quot; alt=&quot;Static credential model versus workload identity federation model. Static model shows two credentials to rotate with a 90 day rotation burden. Federation model shows zero static credentials with tokens valid for a short lifetime, eliminating rotation. Issued by Snowflake as OIDC provider.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: Static credentials require rotation across two integration types with a 90-day operational burden. Workload identity federation eliminates static credentials by issuing short-lived OIDC tokens. Source: Snowflake documentation.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The chart above shows the operational difference: two credentials to rotate with a 90-day burden in the static model, versus zero static credentials and a token lifetime measured in minutes under federation.&lt;/p&gt;
&lt;h2 id=&quot;how-does-this-behave-under-replication-and-failover&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/#how-does-this-behave-under-replication-and-failover&quot;&gt;&lt;span&gt;How does this behave under replication and failover?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where Snowflake&#39;s design choice to be the OIDC provider pays off. The docs are explicit about three replication properties. First, the federated identity is preserved across failover: the secret&#39;s issuer URL and subject identifier replicate unchanged, so after a failover the external service continues to recognise the same &lt;code&gt;iss&lt;/code&gt; and &lt;code&gt;sub&lt;/code&gt; claims. Second, &lt;strong&gt;ID tokens can only be issued from the primary account&lt;/strong&gt;. Calling &lt;code&gt;SYSTEM$ISSUE_WORKLOAD_IDENTITY_FEDERATION_TOKEN&lt;/code&gt; in an account that is a read-only secondary fails. Third, token verification continues to work after failover because the issuer URL automatically resolves to the current primary account, which publishes the public keys the service uses to verify the token signature. You do not need to update the external service&#39;s configuration after a failover.&lt;/p&gt;
&lt;p&gt;For teams running business continuity drills, this matters. A common failure mode with static credentials in a replicated setup is that the credential works in the primary but the external service&#39;s allow-list is pinned to a specific endpoint or account identifier that changes after failover. With workload identity federation, the trust relationship is defined by the issuer URL and subject, both of which follow the primary, so the failover is transparent to the external service as long as it can reach the issuer URL.&lt;/p&gt;
&lt;p&gt;The one constraint to plan for is that token issuance is primary-only. If you have a workload running in a secondary account that calls external services, it cannot mint tokens until it becomes the primary. Design those workloads to either tolerate token issuance failure during a failover window or defer external calls until promotion completes.&lt;/p&gt;
&lt;h2 id=&quot;what-privileges-and-limits-apply&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/#what-privileges-and-limits-apply&quot;&gt;&lt;span&gt;What privileges and limits apply?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The secret is a schema-level object, so the standard &lt;code&gt;CREATE SECRET&lt;/code&gt; privilege and &lt;code&gt;USAGE&lt;/code&gt; on the containing database and schema apply. To issue tokens, the executing role needs &lt;code&gt;USAGE&lt;/code&gt; on the secret. The relevant grants look 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;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; SECRET my_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;my_workload
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE my_pipeline_role&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the only privilege the workload role needs. It does not need access to any external credential, and it does not need a stored key. From a governance standpoint, this tightens the blast radius considerably. If you pair this with the approach in our &lt;a href=&quot;https://data-today.net/snowflake/snowflake-governance-rbac/&quot;&gt;Snowflake RBAC and masking guide&lt;/a&gt;, you can isolate external-service access to a single role that holds nothing but &lt;code&gt;USAGE&lt;/code&gt; on the WIF secret, which is about as narrow as a privilege model gets.&lt;/p&gt;
&lt;p&gt;The docs do not publish a hard rate limit on &lt;code&gt;SYSTEM$ISSUE_WORKLOAD_IDENTITY_FEDERATION_TOKEN&lt;/code&gt;, but the design is clearly built for on-demand issuance per call to an external service, not for caching tokens at high frequency. Tokens are short-lived by OIDC convention, so a workload that calls an external API hundreds of times per minute should cache the token for its lifetime and reuse it, then request a new one when it expires. Caching logic belongs in your UDF or stored procedure, not in the secret.&lt;/p&gt;
&lt;h2 id=&quot;how-is-it-billed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/#how-is-it-billed&quot;&gt;&lt;span&gt;How is it billed?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the question that usually has a catch, and here it does not. Workload identity federation introduces &lt;strong&gt;no additional credit charge&lt;/strong&gt;. The secret is a metadata object. The token issuance function runs in the cloud services layer, not in a virtual warehouse, so it does not consume compute credits. The only cost surface is the warehouse that your UDF, stored procedure, or task runs in, and that is cost you were already paying before you switched from a static credential to a federated token.&lt;/p&gt;
&lt;p&gt;If you want to confirm this in your own account, query the &lt;code&gt;ACCESS_HISTORY&lt;/code&gt; view in &lt;code&gt;SNOWFLAKE.ACCOUNT_USAGE&lt;/code&gt; to see which objects called the token function and whether any warehouse was involved:&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; query_text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; user_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; role_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       warehouse_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; start_time
&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; query_text &lt;span class=&quot;token operator&quot;&gt;ILIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;%SYSTEM$ISSUE_WORKLOAD_IDENTITY_FEDERATION_TOKEN%&#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;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; start_time &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;If &lt;code&gt;warehouse_name&lt;/code&gt; is null for those rows, the function executed in the cloud services layer and consumed no compute credits. That is the expected result.&lt;/p&gt;
&lt;h2 id=&quot;when-is-it-the-wrong-choice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/#when-is-it-the-wrong-choice&quot;&gt;&lt;span&gt;When is it the wrong choice?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This feature is not universal. The external service must support OIDC token verification, and specifically must let you configure a custom issuer URL and expected subject. Many SaaS APIs do. Some older or internal services do not, and for those you are stuck with API keys or OAuth refresh tokens for now. Before you invest in migrating a pipeline, confirm the external service&#39;s documentation supports configuring a custom OIDC issuer and audience validation.&lt;/p&gt;
&lt;p&gt;The primary-only token issuance constraint also makes this a poor fit for active-active architectures where both accounts in a replication pair need to call external services simultaneously. You can only issue from the current primary, so a workload in a secondary account that needs to authenticate externally will fail until promotion. If your DR strategy requires the secondary to be continuously operational against external APIs, you need a static credential fallback or a different architecture.&lt;/p&gt;
&lt;p&gt;Finally, if your external service cannot reach Snowflake&#39;s issuer URL over the public internet to fetch public keys, token verification will fail. This is not a feature for air-gapped or fully private endpoint scenarios unless the external service supports fetching keys from a Snowflake internal endpoint, which the current GA docs do not describe.&lt;/p&gt;
&lt;h2 id=&quot;what-should-you-do-with-it-now&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/#what-should-you-do-with-it-now&quot;&gt;&lt;span&gt;What should you do with it now?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start with the highest-risk pipeline you have: the one where a static API key is stored in a secret and used by a task or UDF to call an external service. That is your first migration candidate because it has the most to lose from credential theft and the most to gain from elimination of rotation. Audit those secrets first:&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; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; secret_type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; created_on&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; last_altered
&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;SECRETS
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; secret_type &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;PASSWORD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;OAUTH&#39;&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; created_on&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For each secret, check whether the downstream service supports OIDC. If it does, create a &lt;code&gt;WORKLOAD_IDENTITY_FEDERATION&lt;/code&gt; secret, register the issuer and subject with the service, swap the token issuance call into your UDF or procedure, and drop the static secret. Test in a non-production account first, and specifically test a failover drill to confirm the external service still authenticates after promotion.&lt;/p&gt;
&lt;p&gt;Do not try to migrate every integration at once. Pick one, get the trust flow working end to end, and document the external service&#39;s configuration steps for your team. The external-side setup is the part that varies the most and the part that will eat your time.&lt;/p&gt;
&lt;h2 id=&quot;the-real-shift&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-workload-identity-federation-guide/#the-real-shift&quot;&gt;&lt;span&gt;The real shift&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Workload identity federation is a quiet change with an outsized payoff. Snowflake is making a claim about where trust should live in a data platform: not in a vault of static keys that engineers have to babysit, but in the platform itself, issuing ephemeral credentials that expire before anyone can abuse them. For a data engineer, that is one fewer rotation ticket, one fewer 2 a.m. page, and one fewer entry in the secret-scanning audit. For a security team, it is a measurable reduction in standing credential risk. The cost is zero. The migration is incremental. The reason not to start is shrinking.&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-workload-identity-federation-guide/#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/workload-identity-federation-outbound&quot;&gt;Snowflake Documentation: Workload identity federation for Snowflake workloads that access external services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-07-01-wif-snowflake-workloads-external-services&quot;&gt;Snowflake Release Notes: July 1, 2026, Workload identity federation GA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/functions/system_issue_workload_identity_federation_token&quot;&gt;Snowflake Documentation: SYSTEM$ISSUE_WORKLOAD_IDENTITY_FEDERATION_TOKEN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Dynamic Iceberg table replication, costed honestly</title>
    <link href="https://data-today.net/snowflake/snowflake-dynamic-iceberg-replication/" />
    <updated>2026-06-29T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-dynamic-iceberg-replication/</id>
    <content type="html">&lt;p&gt;Dynamic Iceberg table replication fixes a small sentence with a big blast radius. If you used dynamic Iceberg tables for lakehouse transforms, your DR plan had an awkward hole: the table could live in a database that replicated, while the dynamic Iceberg table itself got skipped.&lt;/p&gt;
&lt;p&gt;On June 29, 2026, Snowflake made &lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-06-29-dynamic-iceberg-table-replication-ga&quot;&gt;dynamic Iceberg table replication generally available&lt;/a&gt;, saying dynamic Iceberg tables are now supported in replication and failover groups. The key number is &lt;strong&gt;1 missing object class&lt;/strong&gt;: the pipeline output that used to fall out of refresh operations can now travel with the group.&lt;/p&gt;
&lt;p&gt;That matters if your Iceberg estate is no longer just raw lake data. Dynamic Iceberg tables combine scheduled Snowflake transforms with Iceberg output, so Spark, Trino, or another engine can read the materialized result directly. Snowflake says a dynamic Iceberg table stores output in Apache Iceberg format on Snowflake managed external storage and supports the same refresh modes and scheduling as a regular dynamic table, while external engines can read the data directly through the Iceberg files.&lt;/p&gt;
&lt;p&gt;The vendor honest read: this is good DR plumbing, not magic. You still have to replicate the database, include the external volume, configure storage access in the target region, pay replication costs on the target account, and keep an eye on the dynamic table refresh bill. If you skip those parts, GA is just a nicer error message waiting for a maintenance window.&lt;/p&gt;
&lt;h2 id=&quot;what-actually-changes-for-a-dynamic-iceberg-table-in-dr&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-iceberg-replication/#what-actually-changes-for-a-dynamic-iceberg-table-in-dr&quot;&gt;&lt;span&gt;What actually changes for a dynamic Iceberg table in DR?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before this release, Snowflake says dynamic Iceberg tables were skipped during replication refresh operations. After the June 29, 2026 release, Snowflake says &lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-06-29-dynamic-iceberg-table-replication-ga&quot;&gt;replication supports dynamic Iceberg tables&lt;/a&gt; as part of replication and failover groups.&lt;/p&gt;
&lt;p&gt;That is the whole feature, and it is enough.&lt;/p&gt;
&lt;p&gt;A dynamic Iceberg table is still created with &lt;code&gt;CREATE DYNAMIC ICEBERG TABLE&lt;/code&gt;. Snowflake&#39;s dynamic Iceberg guide says the create statement requires the Iceberg specific &lt;code&gt;EXTERNAL_VOLUME&lt;/code&gt;, &lt;code&gt;CATALOG&lt;/code&gt;, and &lt;code&gt;BASE_LOCATION&lt;/code&gt; parameters when you use an external volume, and the documented example uses a &lt;code&gt;TARGET_LAG&lt;/code&gt; of &lt;strong&gt;10 minutes&lt;/strong&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; &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 ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_gold&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_orders_iceberg
    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
    EXTERNAL_VOLUME &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;exvol_lake_gold&#39;&lt;/span&gt;
    CATALOG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;SNOWFLAKE&#39;&lt;/span&gt;
    BASE_LOCATION &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dt_orders_iceberg&#39;&lt;/span&gt;
    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;
        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&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;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;A quick verification step belongs in your runbook because Snowflake exposes an &lt;code&gt;is_iceberg&lt;/code&gt; flag in &lt;code&gt;SHOW DYNAMIC TABLES&lt;/code&gt;; Snowflake&#39;s example shows &lt;code&gt;is_iceberg&lt;/code&gt; returning &lt;code&gt;true&lt;/code&gt; for a dynamic Iceberg table.&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; DYNAMIC &lt;span class=&quot;token keyword&quot;&gt;TABLES&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dt_orders_iceberg&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The DR side is group based. Snowflake&#39;s Iceberg replication guide says Snowflake replicates an Iceberg table when you add its parent database to a replication or failover group, but it also says Snowflake managed Iceberg tables rely on external volumes that need extra configuration before replication can work.&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 keyword&quot;&gt;REPLICATION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; rg_lake_gold
    OBJECT_TYPES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DATABASES&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; EXTERNAL VOLUMES
    ALLOWED_DATABASES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; lake_gold
    ALLOWED_EXTERNAL_VOLUMES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; exvol_lake_gold
    ALLOWED_ACCOUNTS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; myorg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prod_dr
    REPLICATION_SCHEDULE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;10 MINUTE&#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 the target account, the replica is still explicit. Snowflake documents the secondary group syntax as &lt;code&gt;AS REPLICA OF &amp;lt;org_name&amp;gt;.&amp;lt;source_account_name&amp;gt;.&amp;lt;name&amp;gt;&lt;/code&gt; for replication groups.&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 keyword&quot;&gt;REPLICATION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; rg_lake_gold
    &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; REPLICA &lt;span class=&quot;token keyword&quot;&gt;OF&lt;/span&gt; myorg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prod_primary&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rg_lake_gold&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;REPLICATION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; rg_lake_gold REFRESH&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The shape of the design is simple: &lt;strong&gt;database plus external volume&lt;/strong&gt;. If your table depends on an external volume and the group only includes &lt;code&gt;DATABASES&lt;/code&gt;, you have copied the catalog object without the storage access object that makes it useful.&lt;/p&gt;
&lt;h2 id=&quot;which-snowflake-objects-and-privileges-do-you-need&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-iceberg-replication/#which-snowflake-objects-and-privileges-do-you-need&quot;&gt;&lt;span&gt;Which Snowflake objects and privileges do you need?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are two DR paths, and they carry different operational meaning. A replication group gives you a secondary copy. A failover group is the route when you want planned promotion of the secondary account.&lt;/p&gt;
&lt;p&gt;Snowflake&#39;s &lt;code&gt;CREATE REPLICATION GROUP&lt;/code&gt; reference says database and share replication are available to all accounts, while replication of other account objects and failover or failback require Business Critical Edition or higher. Snowflake&#39;s &lt;code&gt;CREATE FAILOVER GROUP&lt;/code&gt; reference is stricter: the command itself &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-failover-group&quot;&gt;requires Business Critical Edition or higher&lt;/a&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;Use it when&lt;/th&gt;
&lt;th&gt;Edition or privilege detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Replication group&lt;/td&gt;
&lt;td&gt;You need a readable secondary copy of the database and external volume object&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE REPLICATION GROUP&lt;/code&gt; on the account, &lt;code&gt;MONITOR&lt;/code&gt; on the database, and &lt;code&gt;USAGE&lt;/code&gt; on the external volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failover group&lt;/td&gt;
&lt;td&gt;You need failover and failback planning for the secondary account&lt;/td&gt;
&lt;td&gt;Business Critical Edition or higher, plus &lt;code&gt;CREATE FAILOVER GROUP&lt;/code&gt; on the account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database or schema backup&lt;/td&gt;
&lt;td&gt;You need backup semantics rather than cross account DR&lt;/td&gt;
&lt;td&gt;Dynamic Iceberg tables are excluded from database or schema backups in Snowflake&#39;s dynamic Iceberg limitations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The privilege model is thankfully concrete. Snowflake says a role creating a replication group needs &lt;code&gt;CREATE REPLICATION GROUP&lt;/code&gt; on the account, &lt;code&gt;MONITOR&lt;/code&gt; on the database being added, and &lt;code&gt;USAGE&lt;/code&gt; on the external volume being added.&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; &lt;span class=&quot;token keyword&quot;&gt;REPLICATION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &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 dr_admin&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; &lt;span class=&quot;token keyword&quot;&gt;DATABASE&lt;/span&gt; lake_gold &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE dr_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; EXTERNAL VOLUME exvol_lake_gold &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE dr_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For failover groups, Snowflake says the corresponding minimums are &lt;code&gt;CREATE FAILOVER GROUP&lt;/code&gt; on the account, &lt;code&gt;MONITOR&lt;/code&gt; on the database, and &lt;code&gt;USAGE&lt;/code&gt; on the external volume.&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; FAILOVER &lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &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 dr_admin&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; &lt;span class=&quot;token keyword&quot;&gt;DATABASE&lt;/span&gt; lake_gold &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE dr_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; EXTERNAL VOLUME exvol_lake_gold &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE dr_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is one more setup step that is easy to bury in a platform ticket. Snowflake&#39;s Iceberg replication guide says a user with the &lt;code&gt;ORGADMIN&lt;/code&gt; role must enable replication for each source and target account in the organization.&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;USE&lt;/span&gt; ROLE ORGADMIN&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; SYSTEM$GLOBAL_ACCOUNT_SET_PARAMETER&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;MYORG.PROD_PRIMARY&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;ENABLE_ACCOUNT_DATABASE_REPLICATION&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;true&#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 lock down advice: do not run this forever as &lt;code&gt;ACCOUNTADMIN&lt;/code&gt;. Create a narrow DR role, grant the three required privileges, and make every group definition code reviewed. The dangerous part is not the refresh command. The dangerous part is a broad &lt;code&gt;OBJECT_TYPES&lt;/code&gt; list that quietly expands the blast radius.&lt;/p&gt;
&lt;h2 id=&quot;how-does-dynamic-iceberg-table-replication-get-billed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-iceberg-replication/#how-does-dynamic-iceberg-table-replication-get-billed&quot;&gt;&lt;span&gt;How does dynamic Iceberg table replication get billed?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake splits replication cost into data transfer and compute resources, and it bills both categories to the target account that stores the secondary database or secondary replication or failover group. Snowflake also says replication compute appears with service type &lt;code&gt;REPLICATION&lt;/code&gt; in Account Usage and Organization Usage views.&lt;/p&gt;
&lt;p&gt;That target account detail is the budget trap. Your primary warehouse owner can ship a new dynamic Iceberg table, while the DR account absorbs refresh transfer and replication compute. If FinOps only watches the primary account, the bill moves sideways and looks like a mystery.&lt;/p&gt;
&lt;p&gt;Snowflake&#39;s replication cost page gives two levers that matter every week: monthly billing is proportional to the amount of changed table data and the frequency of refreshes. For failover groups using optimized refresh, Snowflake documents &lt;strong&gt;5 credits per TB&lt;/strong&gt; of replicated data and &lt;strong&gt;0.2 credits per 10,000 changed objects&lt;/strong&gt; after the first 25,000,000 changed objects per account per month.&lt;/p&gt;
&lt;p&gt;Dynamic table cost is separate from replication cost. Snowflake&#39;s dynamic table cost guide says dynamic tables have three cost components: virtual warehouse compute, Cloud Services compute, and storage, while dynamic Apache Iceberg tables use external storage and do not incur Snowflake storage costs for that materialized output. If you want the broader refresh economics, we covered the mechanics in &lt;a href=&quot;https://data-today.net/snowflake/snowflake-dynamic-tables-refresh/&quot;&gt;our dynamic table refresh cost test&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Your first cost query should prove replication spend from the target account.&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;
    replication_group_name&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;&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 punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&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; 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;bytes_transferred&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; bytes_transferred
&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;replication_group_usage_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;30&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; usage_date &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&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;Your second query should prove whether the dynamic table itself is churning. Snowflake&#39;s &lt;code&gt;DYNAMIC_TABLE_REFRESH_HISTORY&lt;/code&gt; Account Usage view retains &lt;strong&gt;365 days&lt;/strong&gt; of refresh history and includes &lt;code&gt;REFRESH_ACTION&lt;/code&gt;, &lt;code&gt;STATE&lt;/code&gt;, &lt;code&gt;QUERY_ID&lt;/code&gt;, timing columns, and row statistics.&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;
    database_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    schema_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    refresh_action&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    state&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; refreshes&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;&lt;span class=&quot;token keyword&quot;&gt;statistics&lt;/span&gt;:numInsertedRows::number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; inserted_rows&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;&lt;span class=&quot;token keyword&quot;&gt;statistics&lt;/span&gt;:numDeletedRows::number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; deleted_rows
&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;dynamic_table_refresh_history
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; data_timestamp &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; database_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;LAKE_GOLD&#39;&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 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 number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&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; refreshes &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;Use the chart below as the monitoring rule of thumb: Information Schema is the short window for live debugging, while Account Usage is the durable audit trail. Snowflake documents &lt;strong&gt;14 days&lt;/strong&gt; for the replication usage table function and &lt;strong&gt;365 days&lt;/strong&gt; for the Account Usage replication group usage view.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-dynamic-iceberg-replication-fig-replication-usage-windows.png&quot; alt=&quot;Replication usage history retention is 14 days in Information Schema table functions and 365 days in the Account Usage REPLICATION_GROUP_USAGE_HISTORY view.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Snowflake monitoring documentation lists 14 days for Information Schema replication usage functions and 365 days for the Account Usage REPLICATION_GROUP_USAGE_HISTORY view. Source: Snowflake documentation. Data Today benchmark.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;That difference should change where you put dashboards. If an incident review happens on day 21, the 14 day function is already gone. Account Usage is where the postmortem survives.&lt;/p&gt;
&lt;h2 id=&quot;what-breaks-if-the-external-volume-is-wrong&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-iceberg-replication/#what-breaks-if-the-external-volume-is-wrong&quot;&gt;&lt;span&gt;What breaks if the external volume is wrong?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The refresh fails. There is no glamorous answer here.&lt;/p&gt;
&lt;p&gt;Snowflake&#39;s Iceberg replication guide says replicated tables require access to a storage location in the same region as the target account, and it warns that refresh operations can fail if Snowflake cannot access the target account&#39;s storage location.&lt;/p&gt;
&lt;p&gt;The external volume setup is easy to under-specify because the table DDL hides it behind one object name. Snowflake&#39;s sample workflow adds a storage location to the external volume, retrieves the target account&#39;s Snowflake service principal with &lt;code&gt;SYSTEM$DESC_ICEBERG_ACCESS_IDENTITY&lt;/code&gt;, and then creates the replication or failover group with &lt;code&gt;EXTERNAL VOLUMES&lt;/code&gt; in &lt;code&gt;OBJECT_TYPES&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; &lt;span class=&quot;token keyword&quot;&gt;REPLICATION&lt;/span&gt; ACCOUNTS &lt;span class=&quot;token operator&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;PROD_DR%&#39;&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; SYSTEM$DESC_ICEBERG_ACCESS_IDENTITY&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;S3&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;PROD_DR&#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;Then include the external volume in the group. Snowflake explicitly documents &lt;code&gt;ALLOWED_EXTERNAL_VOLUMES&lt;/code&gt; for both replication and failover groups.&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; &lt;span class=&quot;token keyword&quot;&gt;REPLICATION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; rg_lake_gold &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt;
    OBJECT_TYPES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DATABASES&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; EXTERNAL VOLUMES
    ALLOWED_EXTERNAL_VOLUMES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; exvol_lake_gold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two caveats deserve sticky notes. First, Snowflake says secondary tables in the target account are read only until you promote the target account to serve as the source account. Second, Snowflake says an external volume can only be added to one replication or failover group.&lt;/p&gt;
&lt;p&gt;That second rule shapes your topology. A shared external volume across too many domains can block clean DR group boundaries. If finance, product analytics, and ML features all write through one external volume, your replication groups inherit that coupling.&lt;/p&gt;
&lt;h2 id=&quot;when-should-you-use-this-and-when-should-you-hold-back&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-iceberg-replication/#when-should-you-use-this-and-when-should-you-hold-back&quot;&gt;&lt;span&gt;When should you use this, and when should you hold back?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use dynamic Iceberg table replication when the dynamic Iceberg table is a production contract. That usually means at least one of three things is true:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A downstream engine such as Spark or Trino reads the Iceberg output directly.&lt;/li&gt;
&lt;li&gt;The table is part of a recovery time objective that already names a secondary Snowflake account.&lt;/li&gt;
&lt;li&gt;Rebuilding the table from raw data would violate your recovery point objective or burn too many warehouse credits during an outage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hold back when the table is cheap to rebuild, experimental, or downstream only inside one Snowflake account. Replicating every derived object feels safe until every 10 minute schedule becomes a metronome for target account charges.&lt;/p&gt;
&lt;p&gt;The practical rollout is four steps.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Inventory dynamic Iceberg tables with &lt;code&gt;SHOW DYNAMIC TABLES&lt;/code&gt; and the &lt;code&gt;is_iceberg&lt;/code&gt; flag.&lt;/li&gt;
&lt;li&gt;Put only production databases and their external volumes into the first replication group.&lt;/li&gt;
&lt;li&gt;Run a manual &lt;code&gt;ALTER REPLICATION GROUP ... REFRESH&lt;/code&gt; before setting a schedule.&lt;/li&gt;
&lt;li&gt;Watch &lt;code&gt;REPLICATION_GROUP_USAGE_HISTORY&lt;/code&gt; and &lt;code&gt;DYNAMIC_TABLE_REFRESH_HISTORY&lt;/code&gt; for 7 days before expanding scope.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here is the inventory query pattern once the &lt;code&gt;SHOW&lt;/code&gt; output is captured with &lt;code&gt;RESULT_SCAN&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; DYNAMIC &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;DATABASE&lt;/span&gt; lake_gold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;database_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;schema_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;refresh_mode&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;scheduling_state&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;is_iceberg&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;RESULT_SCAN&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LAST_QUERY_ID&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;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;is_iceberg&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;true&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The strongest bet: use this for DR coverage of curated Iceberg outputs that other engines consume. The weak bet: using it as a blanket substitute for pipeline rebuild discipline. Replication preserves objects. It does not prove your transform logic is affordable, your target storage permissions are correct, or your failover game day will pass.&lt;/p&gt;
&lt;h2 id=&quot;the-dr-gap-moved-from-feature-support-to-operating-discipline&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-iceberg-replication/#the-dr-gap-moved-from-feature-support-to-operating-discipline&quot;&gt;&lt;span&gt;The DR gap moved from feature support to operating discipline&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake closed the obvious product gap on June 29, 2026. Dynamic Iceberg table replication now belongs in the standard DR checklist for Iceberg pipelines.&lt;/p&gt;
&lt;p&gt;The new failure mode is more ordinary: a group without &lt;code&gt;EXTERNAL VOLUMES&lt;/code&gt;, a target account nobody budgets, a 10 minute schedule copied from an example, and a runbook that never checks Account Usage. Enterprise data platforms rarely fail because one feature is missing. They fail because the feature arrived, and nobody updated the boring parts.&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-dynamic-iceberg-replication/#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/release-notes/2026/other/2026-06-29-dynamic-iceberg-table-replication-ga&quot;&gt;Snowflake release notes: Dynamic Iceberg table replication, General availability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-replication&quot;&gt;Snowflake documentation: Configure replication for Snowflake managed Apache Iceberg tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/create-iceberg&quot;&gt;Snowflake documentation: Create a dynamic Apache Iceberg table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/account-replication-cost&quot;&gt;Snowflake documentation: Understanding replication cost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/account-replication-monitor&quot;&gt;Snowflake documentation: Monitoring replication and failover&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-replication-group&quot;&gt;Snowflake SQL reference: CREATE REPLICATION GROUP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-failover-group&quot;&gt;Snowflake SQL reference: CREATE FAILOVER GROUP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/dynamic_table_refresh_history&quot;&gt;Snowflake documentation: DYNAMIC_TABLE_REFRESH_HISTORY view&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake Dynamic Tables refresh gets a cost test</title>
    <link href="https://data-today.net/snowflake/snowflake-dynamic-tables-refresh/" />
    <updated>2026-06-22T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-dynamic-tables-refresh/</id>
    <content type="html">&lt;p&gt;Snowflake Dynamic Tables used to be a clean idea with a practical ceiling: great when your transformation fit a SELECT, less great when your pipeline needed CDC semantics, MERGE logic, Iceberg output, or a bill you could explain without squinting. The June 2026 update changes that trade. Snowflake Dynamic Tables now have a claimed &lt;strong&gt;up to 2.8x faster refresh performance&lt;/strong&gt; on popular patterns measured from May 2025 to May 2026 on Gen2 warehouses, plus preview support for custom incrementalization with MERGE and INSERT logic in &lt;code&gt;REFRESH USING&lt;/code&gt;, according to Snowflake&#39;s &lt;a href=&quot;https://www.snowflake.com/en/blog/whats-new-dynamic-tables-faster-flexible/&quot;&gt;June 15 Dynamic Tables blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The useful read for a data engineer is simple: Dynamic Tables are becoming Snowflake&#39;s default managed transformation layer. That does not mean you should port every Stream and Task tomorrow. It means the boundary moved. SELECT based transformations, SCD type 1 dedupe, append heavy aggregates, dbt models, and some CDC style workloads now belong in the Dynamic Tables discussion before you design another orchestration DAG.&lt;/p&gt;
&lt;p&gt;If you are also sizing Gen2 compute, read this alongside our guide to &lt;a href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/&quot;&gt;Snowflake Gen2 warehouses&lt;/a&gt;. The refresh win Snowflake is advertising is tied to Gen2 warehouses, and the bill will still be decided by target lag, refresh mode, reinitializations, and how many tables you keep active.&lt;/p&gt;
&lt;h2 id=&quot;what-actually-got-faster-in-snowflake-dynamic-tables&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-tables-refresh/#what-actually-got-faster-in-snowflake-dynamic-tables&quot;&gt;&lt;span&gt;What actually got faster in Snowflake Dynamic Tables?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake says its benchmark suite for common Dynamic Table patterns improved by &lt;strong&gt;up to 2.8x&lt;/strong&gt; between May 2025 and May 2026, with the tested optimizations covering top level aggregate functions, &lt;code&gt;QUALIFY&lt;/code&gt; row or rank equals 1 patterns for SCD type 1, clustering operations, and joins on Gen2 warehouses in the &lt;a href=&quot;https://www.snowflake.com/en/blog/whats-new-dynamic-tables-faster-flexible/&quot;&gt;product announcement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That matters because Dynamic Tables do two separate jobs. They materialize query results, and they refresh those results on a schedule Snowflake controls from your &lt;code&gt;TARGET_LAG&lt;/code&gt;. In the syntax reference, Snowflake defines &lt;code&gt;TARGET_LAG&lt;/code&gt; as the maximum time the Dynamic Table should lag behind changes to its base tables, with a documented &lt;strong&gt;minimum of 60 seconds&lt;/strong&gt; when the scheduler is enabled in &lt;code&gt;CREATE DYNAMIC TABLE&lt;/code&gt; &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table&quot;&gt;syntax&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A basic production definition should be boring on purpose:&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; mart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_orders_latest
  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
  INITIALIZATION_WAREHOUSE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; init_wh_l
  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; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; EXCLUDE rn
&lt;span class=&quot;token keyword&quot;&gt;FROM&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;
    o&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;
    ROW_NUMBER&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;OVER&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;PARTITION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; order_id
      &lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; updated_at &lt;span class=&quot;token keyword&quot;&gt;DESC&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; rn
  &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders_cdc o
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
QUALIFY rn &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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two details in that snippet are worth copying. First, &lt;code&gt;REFRESH_MODE = INCREMENTAL&lt;/code&gt; makes the behavior deterministic instead of letting &lt;code&gt;AUTO&lt;/code&gt; choose at creation time. Snowflake&#39;s refresh mode docs say &lt;code&gt;AUTO&lt;/code&gt; resolves once when the table is created, then does not keep reevaluating on later refreshes, so production code should pin the mode after testing in &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/refresh-modes&quot;&gt;refresh modes&lt;/a&gt;. Second, &lt;code&gt;INITIALIZATION_WAREHOUSE&lt;/code&gt; lets you separate the warehouse for initializations and reinitializations from the smaller warehouse that handles normal refreshes, as documented in the &lt;code&gt;CREATE DYNAMIC TABLE&lt;/code&gt; &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table&quot;&gt;parameter reference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The best design pattern is still chain shaped. Put cleanup in one Dynamic Table, joins in another, and aggregation in a downstream table. Snowflake documents &lt;code&gt;TARGET_LAG = DOWNSTREAM&lt;/code&gt; for intermediate Dynamic Tables, which refresh only when dependent Dynamic Tables refresh, in the &lt;code&gt;CREATE DYNAMIC TABLE&lt;/code&gt; &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table&quot;&gt;syntax&lt;/a&gt;. That is where you avoid paying for a silver layer that no consumer asked to update.&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; silver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_orders_clean
  TARGET_LAG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; DOWNSTREAM
  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_ts&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders
&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;cancelled&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&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; DYNAMIC &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; gold&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_revenue_hourly
  TARGET_LAG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;15 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; DATE_TRUNC&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hour&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; order_ts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&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 function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; revenue
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; silver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_orders_clean
&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;h2 id=&quot;how-does-the-refresh-mode-choice-change-your-pipeline-design&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-tables-refresh/#how-does-the-refresh-mode-choice-change-your-pipeline-design&quot;&gt;&lt;span&gt;How does the refresh mode choice change your pipeline design?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The big change is that Dynamic Tables now cover more of the space Streams and Tasks used to own. Snowflake&#39;s docs list four Snowflake managed refresh modes, &lt;code&gt;INCREMENTAL&lt;/code&gt;, &lt;code&gt;FULL&lt;/code&gt;, &lt;code&gt;AUTO&lt;/code&gt;, and &lt;code&gt;ADAPTIVE&lt;/code&gt;, plus &lt;code&gt;CUSTOM_INCREMENTAL&lt;/code&gt; for user defined refresh logic in &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/refresh-modes&quot;&gt;refresh modes&lt;/a&gt;. The first three are familiar. The last two are where pipeline design gets interesting.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Status or key behavior&lt;/th&gt;
&lt;th&gt;Use it when&lt;/th&gt;
&lt;th&gt;Cost risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;INCREMENTAL&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Best practice when fewer than &lt;strong&gt;5 percent&lt;/strong&gt; of base data changes between refreshes&lt;/td&gt;
&lt;td&gt;Append heavy tables, SCD type 1 dedupe, ordinary aggregates&lt;/td&gt;
&lt;td&gt;Fails at create time if the query cannot incrementalize&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ADAPTIVE&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Public preview, available to all accounts&lt;/td&gt;
&lt;td&gt;Mostly incremental tables with occasional &lt;code&gt;INSERT OVERWRITE&lt;/code&gt; or bulk updates&lt;/td&gt;
&lt;td&gt;Can reinitialize when Snowflake&#39;s heuristics say full rebuild is cheaper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CUSTOM_INCREMENTAL&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Public preview, available to all accounts&lt;/td&gt;
&lt;td&gt;MERGE or INSERT logic, soft deletes, accumulators, Stream and Task migration&lt;/td&gt;
&lt;td&gt;You own semantics, including nondeterministic MERGE cases&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;strong&gt;5 percent&lt;/strong&gt; number is a guideline, not a hard switch. Snowflake says incremental refresh is typically best when fewer than five percent of the base table data changes between refreshes, and also states that Dynamic Tables do not automatically switch modes based on that threshold in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/refresh-modes&quot;&gt;refresh mode guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ADAPTIVE&lt;/code&gt; is the practical compromise for pipelines that are usually append heavy but occasionally get punched by a bulk operation. Snowflake documents &lt;code&gt;ADAPTIVE&lt;/code&gt; as a public preview mode that uses incremental refresh by default, then automatically reinitializes when internal heuristics detect that incremental refresh would be significantly more expensive than rebuilding from scratch in &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/refresh-modes&quot;&gt;refresh modes&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; &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; mart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_orders_adaptive
  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
  INITIALIZATION_WAREHOUSE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; init_wh_xl
  REFRESH_MODE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ADAPTIVE
&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; amount
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;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;COMPLETED&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CUSTOM_INCREMENTAL&lt;/code&gt; is the more opinionated feature. Snowflake&#39;s custom incrementalization docs say it is a public preview available to all accounts, requires an explicit column list, and allows only &lt;strong&gt;one DML statement&lt;/strong&gt; inside &lt;code&gt;REFRESH USING&lt;/code&gt; in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/custom-incrementalization&quot;&gt;custom incrementalization guide&lt;/a&gt;. That is managed orchestration, not magic. If your old Task ran a stored procedure with three statements and side effects, you still have design work to do.&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; mart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_customer_status &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  customer_id NUMBER&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt; STRING&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updated_at TIMESTAMP_NTZ
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  TARGET_LAG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;5 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; CUSTOM_INCREMENTAL
  REFRESH &lt;span class=&quot;token keyword&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;MERGE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; SELF &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; tgt
    &lt;span class=&quot;token keyword&quot;&gt;USING&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; customer_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updated_at
      &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customer_events CHANGES&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      QUALIFY ROW_NUMBER&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;OVER&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;PARTITION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; customer_id
        &lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; updated_at &lt;span class=&quot;token keyword&quot;&gt;DESC&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;AS&lt;/span&gt; src
    &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; tgt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customer_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; src&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customer_id
    &lt;span class=&quot;token keyword&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;MATCHED&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SET&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; src&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      updated_at &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; src&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;updated_at
    &lt;span class=&quot;token keyword&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;MATCHED&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INSERT&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 keyword&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updated_at&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customer_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; src&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; src&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;updated_at&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;This is where the lock-in gets real. A SELECT based Dynamic Table can often be reasoned about as a materialized transformation. A custom incremental table is Snowflake specific DML wrapped in Snowflake managed scheduling. That may be a good trade if it deletes Airflow glue and Task boilerplate. It is a bad trade if your lakehouse strategy depends on moving that logic across engines next quarter.&lt;/p&gt;
&lt;h2 id=&quot;where-does-the-bill-hide-when-refresh-gets-faster&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-tables-refresh/#where-does-the-bill-hide-when-refresh-gets-faster&quot;&gt;&lt;span&gt;Where does the bill hide when refresh gets faster?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Faster refresh can lower warehouse time, but the recurring tax is refresh frequency. Snowflake says Cloud Services credits cover metadata operations such as change detection, compilation, and scheduling on every refresh cycle, and each active Dynamic Table incurs that overhead independently in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/cost&quot;&gt;Dynamic Table cost guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The chart below shows the ugly arithmetic for a 200 table pipeline. Snowflake&#39;s own example says &lt;strong&gt;200 Dynamic Tables&lt;/strong&gt; at a &lt;strong&gt;1 minute&lt;/strong&gt; target lag produce about &lt;strong&gt;288000 change detection checks per day&lt;/strong&gt;. At 10 minutes, the same simple formula drops to 28800. At 60 minutes, it drops to 4800.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-dynamic-tables-refresh-fig-change-detection-checks.png&quot; alt=&quot;Bar chart for Snowflake Dynamic Tables showing 200 tables at 1 minute target lag produce 288000 daily change detection checks, 10 minutes produces 28800, and 60 minutes produces 4800.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Illustrative: Snowflake documentation states that 200 active Dynamic Tables at a 1 minute target lag generate about 288000 change detection checks per day. The same formula gives 28800 checks at 10 minutes and 4800 checks at 60 minutes. Source: Snowflake documentation. Data Today benchmark.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;This is why &lt;code&gt;TARGET_LAG = &#39;1 minute&#39;&lt;/code&gt; should require a product reason, not just an engineer with ambition. Snowflake also says Cloud Services credits are billed only when the daily account total exceeds &lt;strong&gt;10 percent&lt;/strong&gt; of that day&#39;s warehouse compute credits, calculated at the account level in UTC, in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/cost&quot;&gt;cost documentation&lt;/a&gt;. Short lags across deep DAGs are how you turn background metadata into a visible line item.&lt;/p&gt;
&lt;p&gt;Use a dedicated warehouse while testing. Then prove the usage before you move Dynamic Tables onto shared compute:&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;ROUND&lt;/span&gt;&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 punctuation&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;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;ROUND&lt;/span&gt;&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 punctuation&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;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;ROUND&lt;/span&gt;&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 punctuation&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;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; cs_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; total_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;For Adaptive mode, watch reinitializations directly. Snowflake says reinitializations appear as &lt;code&gt;REFRESH_ACTION = &#39;REINITIALIZE&#39;&lt;/code&gt;, with the reason in &lt;code&gt;REINIT_REASON&lt;/code&gt;, through &lt;code&gt;DYNAMIC_TABLE_REFRESH_HISTORY&lt;/code&gt; in &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/refresh-modes&quot;&gt;refresh modes&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;SELECT&lt;/span&gt;
  name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  refresh_action&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  reinit_reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  data_timestamp
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;INFORMATION_SCHEMA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DYNAMIC_TABLE_REFRESH_HISTORY&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  NAME &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;MART.DT_ORDERS_ADAPTIVE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  DATA_TIMESTAMP_START &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&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 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; data_timestamp &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;If that query shows weekly reinitializations on an XL initialization warehouse, your optimization story changed. You may still be saving money compared with slow incremental refresh after bulk rewrites. You just need to budget the rebuilds as a known event, not a spooky warehouse flare.&lt;/p&gt;
&lt;h2 id=&quot;what-should-you-lock-down-before-teams-start-creating-them&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-tables-refresh/#what-should-you-lock-down-before-teams-start-creating-them&quot;&gt;&lt;span&gt;What should you lock down before teams start creating them?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dynamic Tables are operational objects. Treat them like pipelines, not like tables someone happened to create in a worksheet. Snowflake&#39;s access control guide says creating one requires &lt;code&gt;CREATE DYNAMIC TABLE&lt;/code&gt; on the schema, &lt;code&gt;SELECT&lt;/code&gt; on referenced base objects, and &lt;code&gt;USAGE&lt;/code&gt; on the database, schema, and refresh warehouse in &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/privileges&quot;&gt;Dynamic Table privileges&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; &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 transform_role&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;mart &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE transform_role&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 transform_wh &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE transform_role&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; DYNAMIC &lt;span class=&quot;token keyword&quot;&gt;TABLE&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;mart &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE transform_role&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;TABLE&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE transform_role&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The owner role is the sleeper risk. Snowflake says the owner role runs background refreshes and must keep &lt;code&gt;USAGE&lt;/code&gt; and &lt;code&gt;SELECT&lt;/code&gt; on referenced objects, or refreshes fail, in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/privileges&quot;&gt;privileges guide&lt;/a&gt;. That means your production owner should be a service role with boring, durable grants. Do not let a project role own a critical mart if that role gets cleaned up after the migration sprint.&lt;/p&gt;
&lt;p&gt;Give operators &lt;code&gt;OPERATE&lt;/code&gt;, not &lt;code&gt;OWNERSHIP&lt;/code&gt;, when they need to suspend, resume, or manually refresh. Give observability users &lt;code&gt;MONITOR&lt;/code&gt;, which Snowflake documents as read only access to scheduling state, refresh history, and graph history in &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/privileges&quot;&gt;Dynamic Table privileges&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; OPERATE &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; DYNAMIC &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; analytics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_orders_adaptive
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE pipeline_admin_role&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; FUTURE DYNAMIC &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;mart
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE data_ops_role&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also decide your retention strategy before you build historical aggregates. Frozen regions let you declare rows that refresh should skip. Snowflake documents &lt;code&gt;BACKFILL FROM&lt;/code&gt; as a create time option that copies existing data into a new Dynamic Table without recomputing it, and says it cannot be added later with &lt;code&gt;ALTER&lt;/code&gt; in &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/frozen-regions&quot;&gt;frozen regions and backfill&lt;/a&gt;. That is perfect for migrating a years old daily aggregate, as long as you accept that frozen rows are intentionally stale.&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; mart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_orders_daily
  TARGET_LAG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;1 hour&#39;&lt;/span&gt;
  WAREHOUSE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transform_wh
  FROZEN &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;order_day &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&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 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;
  BACKFILL &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; mart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dt_orders_daily_legacy
&lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&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 string&quot;&gt;&#39;day&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; order_ts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; order_day&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  region&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; order_count&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;amount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; revenue
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orders_enriched
&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 punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Storage lifecycle policies are now generally available for Dynamic Tables. Snowflake&#39;s May 21, 2026 release note says a policy can delete or archive matching rows on its own schedule, and rows in the expired region are treated as frozen by refresh in the &lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-05-21-storage-lifecycle-policies-dynamic-tables-ga&quot;&gt;GA release note&lt;/a&gt;. That gives you a cleaner pattern for keeping raw or intermediate data short lived while keeping aggregates available.&lt;/p&gt;
&lt;h2 id=&quot;when-should-you-still-use-streams-and-tasks-instead&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-tables-refresh/#when-should-you-still-use-streams-and-tasks-instead&quot;&gt;&lt;span&gt;When should you still use Streams and Tasks instead?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Keep Streams and Tasks when your pipeline is multi statement, procedural, or intentionally outside Dynamic Table semantics. Snowflake&#39;s custom incremental docs allow only one DML statement inside &lt;code&gt;REFRESH USING&lt;/code&gt;, and they call out that stored procedures, UDTFs, or multi statement transactions need restructuring in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/custom-incrementalization&quot;&gt;custom incrementalization guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Use Dynamic Tables first when the transformation is naturally SQL shaped and freshness is the product requirement. Use Streams and Tasks first when the workflow is a job with side effects: call an external service, write audit records in multiple places, conditionally branch across several tables, or coordinate work that must run exactly once after a non-Snowflake event.&lt;/p&gt;
&lt;p&gt;The dbt story is practical but not free. Snowflake documents &lt;code&gt;dynamic_table&lt;/code&gt; as a dbt materialization, and says SQL changes to a model trigger &lt;code&gt;CREATE OR REPLACE&lt;/code&gt;, which causes reinitialization, while config only changes such as target lag and warehouse can be applied with &lt;code&gt;ALTER&lt;/code&gt; when &lt;code&gt;on_configuration_change&lt;/code&gt; is set to &lt;code&gt;apply&lt;/code&gt; in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/dbt&quot;&gt;dbt integration docs&lt;/a&gt;. Translation: dbt plus Dynamic Tables is attractive for model discipline, but casual SELECT edits can become rebuilds.&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; DYNAMIC &lt;span class=&quot;token keyword&quot;&gt;TABLES&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dt_orders_daily&#39;&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;mart&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check &lt;code&gt;refresh_mode&lt;/code&gt;, &lt;code&gt;warehouse&lt;/code&gt;, &lt;code&gt;scheduling_state&lt;/code&gt;, &lt;code&gt;target_lag&lt;/code&gt;, &lt;code&gt;is_iceberg&lt;/code&gt;, and &lt;code&gt;immutable_where&lt;/code&gt;. Snowflake documents those fields in &lt;code&gt;SHOW DYNAMIC TABLES&lt;/code&gt;, including &lt;code&gt;refresh_mode&lt;/code&gt; values for &lt;code&gt;INCREMENTAL&lt;/code&gt;, &lt;code&gt;FULL&lt;/code&gt;, &lt;code&gt;AUTO&lt;/code&gt;, &lt;code&gt;ADAPTIVE&lt;/code&gt;, and &lt;code&gt;CUSTOM_INCREMENTAL&lt;/code&gt; in the &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/show-dynamic-tables&quot;&gt;SHOW DYNAMIC TABLES reference&lt;/a&gt;. If the metadata does not match your design doc, the bill will follow the metadata.&lt;/p&gt;
&lt;h2 id=&quot;the-sharp-edge-is-no-longer-expressibility-it-is-control&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-dynamic-tables-refresh/#the-sharp-edge-is-no-longer-expressibility-it-is-control&quot;&gt;&lt;span&gt;The sharp edge is no longer expressibility. It is control.&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake closed a real gap. Faster Dynamic Tables on Gen2 warehouses, Adaptive refresh, frozen regions, backfill, dbt support, Iceberg output, and preview custom incrementalization make the feature much harder to dismiss as a prettier materialized view.&lt;/p&gt;
&lt;p&gt;The next failure mode is overuse. A one minute lag on 200 tables creates 288000 daily checks. A custom incremental table can hide business semantics inside a Snowflake specific &lt;code&gt;MERGE INTO SELF&lt;/code&gt;. A dbt model edit can trigger reinitialization. None of that makes the feature bad. It makes ownership matter.&lt;/p&gt;
&lt;p&gt;The right move is boring and effective: pick one production pipeline, pin &lt;code&gt;REFRESH_MODE&lt;/code&gt;, use Gen2 compute, set intermediate tables to &lt;code&gt;DOWNSTREAM&lt;/code&gt;, split initialization and refresh warehouses, grant &lt;code&gt;MONITOR&lt;/code&gt; broadly, and watch &lt;code&gt;DYNAMIC_TABLE_REFRESH_HISTORY&lt;/code&gt; for seven days. If the latency drops and the credit curve stays flat, expand. If it does not, you learned before the pipeline became a platform.&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-dynamic-tables-refresh/#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://www.snowflake.com/en/blog/whats-new-dynamic-tables-faster-flexible/&quot;&gt;Snowflake Blog: What&#39;s New with Dynamic Tables: Faster and More Flexible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table&quot;&gt;Snowflake documentation: CREATE DYNAMIC TABLE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/refresh-modes&quot;&gt;Snowflake documentation: Dynamic table refresh modes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/custom-incrementalization&quot;&gt;Snowflake documentation: Custom incrementalization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/cost&quot;&gt;Snowflake documentation: Understanding costs for dynamic tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/privileges&quot;&gt;Snowflake documentation: Dynamic table access control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/frozen-regions&quot;&gt;Snowflake documentation: Frozen regions and backfill&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/dynamic-tables/dbt&quot;&gt;Snowflake documentation: Use dynamic tables in dbt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/show-dynamic-tables&quot;&gt;Snowflake documentation: SHOW DYNAMIC TABLES&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-05-21-storage-lifecycle-policies-dynamic-tables-ga&quot;&gt;Snowflake release notes: Storage lifecycle policies for dynamic tables, General availability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-05-26-dynamic-tables-custom-incremental&quot;&gt;Snowflake release notes: Custom incremental dynamic tables, Public Preview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake Adaptive Compute changes AWS cost models</title>
    <link href="https://data-today.net/snowflake/snowflake-adaptive-compute-ga/" />
    <updated>2026-06-22T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-adaptive-compute-ga/</id>
    <content type="html">&lt;p&gt;Snowflake has spent years training data teams to think in warehouse sizes. XS for cheap work. XL for impatient executives. Multi-cluster when the BI crowd arrives at 9:03 a.m. Snowflake Adaptive Compute changes that muscle memory.&lt;/p&gt;
&lt;p&gt;The feature is now generally available on AWS, and the important number is &lt;strong&gt;1.2x&lt;/strong&gt;: Snowflake says Snowflake Adaptive Compute delivered 1.2x better price-performance than Gen2 standard warehouses on its TPC-DS 10TB Concurrency Benchmark in the &lt;a href=&quot;https://www.snowflake.com/en/blog/adaptive-compute-generally-available/&quot;&gt;June 16, 2026 GA announcement&lt;/a&gt;. That is useful, but it is also vendor benchmark math. The operational change matters more: Adaptive Warehouses replace fixed warehouse sizing with per-query scheduling and query-based billing, so your FinOps model moves from uptime math toward query attribution.&lt;/p&gt;
&lt;p&gt;If you already read our earlier bill-owner framing for &lt;a href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-costs/&quot;&gt;Adaptive Compute costs&lt;/a&gt;, the GA update narrows the action: AWS customers in six named regions can now run production conversion tests instead of treating this as roadmap theater.&lt;/p&gt;
&lt;h2 id=&quot;what-actually-changed-in-snowflake-adaptive-compute-ga&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-ga/#what-actually-changed-in-snowflake-adaptive-compute-ga&quot;&gt;&lt;span&gt;What actually changed in Snowflake Adaptive Compute GA?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake Adaptive Compute is exposed through Adaptive Warehouses. In Snowflake&#39;s docs, Adaptive Warehouses remove the need to manage warehouse size, multi-cluster settings, Query Acceleration Service settings, and suspend or resume policies through the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive&quot;&gt;Adaptive Compute guide&lt;/a&gt;. That is four knobs gone from the day-to-day operating loop.&lt;/p&gt;
&lt;p&gt;You still create a warehouse object. You still grant roles access. You still get warehouse-level chargeback. The difference is that all jobs across Adaptive Warehouses in an account route to a compute pool dedicated to that account, and Snowflake says that pool is separate from standard, interactive, and Snowpark-optimized warehouses in the same &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive&quot;&gt;Adaptive Compute guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The smallest useful DDL is almost rude in its simplicity:&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 finops_adaptive_wh&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 defaults: &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;Adaptive Warehouse creation docs&lt;/a&gt;. Start there before you invent a tuning doctrine.&lt;/p&gt;
&lt;p&gt;For a workload that already needs a tighter cap, use the two Adaptive-specific properties explicitly:&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_burst_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;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; is an upper bound on per-query performance, expressed as t-shirt sizes from &lt;code&gt;XSMALL&lt;/code&gt; through &lt;code&gt;X4LARGE&lt;/code&gt;, and Snowflake says it does not map to a specific underlying compute configuration in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#max-query-performance-level&quot;&gt;performance control docs&lt;/a&gt;. &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt; is the concurrency-ish budget, with default &lt;code&gt;2&lt;/code&gt;; setting it to &lt;code&gt;0&lt;/code&gt; means unlimited throughput subject to available burst capacity in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#query-throughput-multiplier&quot;&gt;throughput multiplier docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That last detail is the trap door. &lt;code&gt;0&lt;/code&gt; sounds convenient during a launch. It is also the number that tells Snowflake, effectively, to stop capping burst throughput at the warehouse property level.&lt;/p&gt;
&lt;h2 id=&quot;where-can-you-run-it-and-what-is-still-missing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-ga/#where-can-you-run-it-and-what-is-still-missing&quot;&gt;&lt;span&gt;Where can you run it, and what is still missing?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake says Adaptive Compute is generally available on AWS in &lt;strong&gt;six regions&lt;/strong&gt;: US West 2 in Oregon, US East 2 in Ohio, EU West 1 in Ireland, EU Central 1 in Frankfurt, AP Northeast 1 in Tokyo, and AP Southeast 2 in Sydney in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#region-availability&quot;&gt;region availability section&lt;/a&gt;. That is enough for real enterprise testing, including some cross-region business continuity pairings, but it is still a selective footprint.&lt;/p&gt;
&lt;p&gt;The chart below shows the launch footprint by geography: 2 Americas regions, 2 Europe regions, and 2 Asia Pacific regions.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-adaptive-compute-ga-fig-ga-region-footprint.png&quot; alt=&quot;Bar chart showing Snowflake Adaptive Compute GA region footprint on AWS: Americas 2 regions, Europe 2 regions, and Asia Pacific 2 regions, for 6 total regions.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Snowflake lists six GA AWS regions for Adaptive Compute: 2 in the Americas, 2 in Europe, and 2 in Asia Pacific. Source: Snowflake documentation. Data Today benchmark.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;There are two hard constraints you should put in the migration ticket. Adaptive Warehouses require Enterprise Edition or higher, and Snowflake lists that limitation in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#limitations&quot;&gt;Adaptive Compute limitations&lt;/a&gt;. Snowflake also says conversion to or from &lt;code&gt;X5LARGE&lt;/code&gt; and &lt;code&gt;X6LARGE&lt;/code&gt; warehouses is unsupported, as are conversions to or from Snowpark-optimized or interactive warehouses in the same limitations section.&lt;/p&gt;
&lt;p&gt;Here is the practical comparison for platform owners:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;What you control&lt;/th&gt;
&lt;th&gt;Cost evidence&lt;/th&gt;
&lt;th&gt;Best production fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Standard Gen2 warehouse&lt;/td&gt;
&lt;td&gt;&lt;code&gt;WAREHOUSE_SIZE&lt;/code&gt;, generation, multi-cluster, QAS settings&lt;/td&gt;
&lt;td&gt;&lt;code&gt;WAREHOUSE_METERING_HISTORY&lt;/code&gt; for 365 days&lt;/td&gt;
&lt;td&gt;Predictable BI or ETL where size policy is already tuned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adaptive Warehouse&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; and &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;QUERY_METERING_HISTORY&lt;/code&gt; per query for 365 days&lt;/td&gt;
&lt;td&gt;Bursty analytics, mixed BI and ETL, spiky SQL from agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interactive or Snowpark-optimized&lt;/td&gt;
&lt;td&gt;Specialized warehouse type, separate from Adaptive conversion&lt;/td&gt;
&lt;td&gt;Warehouse usage views, but no Adaptive conversion path&lt;/td&gt;
&lt;td&gt;Very low latency dashboards or high-memory Snowpark and ML&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The right first candidate is a warehouse with lumpy concurrency and high variance in query shape. The wrong first candidate is your weirdest Snowpark memory hog.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-convert-without-breaking-running-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-ga/#how-do-you-convert-without-breaking-running-work&quot;&gt;&lt;span&gt;How do you convert without breaking running work?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The conversion path is a single property change:&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 reporting_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;Snowflake says conversion to Adaptive Warehouse is an online operation: running queries continue on existing compute while new queries use the new warehouse type, and you can convert back with &lt;code&gt;WAREHOUSE_TYPE = &#39;STANDARD&#39;&lt;/code&gt; in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#convert-a-standard-warehouse-to-an-adaptive-warehouse&quot;&gt;conversion docs&lt;/a&gt;. That makes the feature unusually testable for a warehouse change.&lt;/p&gt;
&lt;p&gt;There is one billing wrinkle you should schedule around. During conversion, Snowflake says existing queries continue on the old compute while new queries run on the new type, and you are charged for both sets of compute resources until the old queries finish in the same &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#convert-a-standard-warehouse-to-an-adaptive-warehouse&quot;&gt;conversion note&lt;/a&gt;. Convert a warehouse during a clean window, not while a 3-hour backfill is already crawling through month-end partitions.&lt;/p&gt;
&lt;p&gt;After conversion, Snowflake computes values for &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; and &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt; from the old configuration, including warehouse size, &lt;code&gt;MAX_CLUSTER_COUNT&lt;/code&gt;, QAS scale factor, and warehouse generation in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#property-behavior-during-conversion&quot;&gt;property behavior docs&lt;/a&gt;. That is a migration convenience, not a substitute for measurement.&lt;/p&gt;
&lt;p&gt;Check what Snowflake gave you:&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;REPORTING_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, &lt;code&gt;SHOW WAREHOUSES&lt;/code&gt; includes &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;, according to the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#show-warehouses-output&quot;&gt;Adaptive Warehouse metadata docs&lt;/a&gt;. Capture those values in the change record. Future you will thank present you, quietly, during the budget review.&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-ga/#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;Adaptive Warehouses use query-based billing, where each query cost depends on compute and software resources used, including cluster sizes and extra capacity from features like QAS, according to Snowflake&#39;s &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#billing-and-pricing&quot;&gt;billing and pricing section&lt;/a&gt;. Snowflake also says you are not charged for creating an Adaptive Warehouse and charges start when the first query runs in that same section.&lt;/p&gt;
&lt;p&gt;This is the core FinOps shift. Standard warehouses train you to ask, &amp;quot;How long was the warehouse running?&amp;quot; Adaptive asks, &amp;quot;Which query burned the credits?&amp;quot;&lt;/p&gt;
&lt;p&gt;Use the new per-query view for the first answer:&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;
  user_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  role_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query_tag&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;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;REPORTING_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_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 keyword&quot;&gt;ALL&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; credits_used &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;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;QUERY_METERING_HISTORY&lt;/code&gt; returns per-query credit usage for Adaptive Warehouse queries over the last 365 days, and Snowflake says the view can lag by up to 1 hour in the &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/query_metering_history&quot;&gt;Account Usage reference&lt;/a&gt;. Each long query can produce multiple rows, one per metering hour, so always &lt;code&gt;SUM(credits_used)&lt;/code&gt; before you point fingers.&lt;/p&gt;
&lt;p&gt;For showback, keep the old hourly warehouse view in place:&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 string&quot;&gt;&#39;day&#39;&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;
  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_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;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;REPORTING_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; &lt;span class=&quot;token keyword&quot;&gt;ALL&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; usage_day&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;WAREHOUSE_METERING_HISTORY&lt;/code&gt; returns hourly warehouse credit usage for the last 365 days, and Snowflake documents &lt;code&gt;CREDITS_USED&lt;/code&gt;, &lt;code&gt;CREDITS_USED_COMPUTE&lt;/code&gt;, and &lt;code&gt;CREDITS_USED_CLOUD_SERVICES&lt;/code&gt; in the &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/warehouse_metering_history&quot;&gt;view reference&lt;/a&gt;. For Adaptive Warehouses, Snowflake says QAS usage is included in compute credits and does not appear as a separate credit column in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#account-and-organization-usage-views&quot;&gt;Adaptive Account Usage section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The price-performance headline is real enough to test, but too blunt to buy on faith. Snowflake&#39;s benchmark says Adaptive Compute is 1.2x better than Gen2 on TPC-DS 10TB concurrency, which normalizes to 1.0 for Gen2 and &lt;strong&gt;1.2&lt;/strong&gt; for Adaptive in the chart.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-adaptive-compute-ga-fig-price-performance-index.png&quot; alt=&quot;Bar chart showing Gen2 standard warehouses at a 1.0 price-performance index and Snowflake Adaptive Compute at 1.2, based on Snowflake&#39;s TPC-DS 10TB Concurrency Benchmark.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Snowflake reports Adaptive Compute at 1.2x Gen2 price-performance on the TPC-DS 10TB Concurrency Benchmark, with Gen2 normalized to 1.0. Source: Snowflake blog. Data Today benchmark.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;A 20 percent benchmark edge can disappear if your workload is dominated by one bad join, a leaky BI extract, or a queue cap you set too low. The feature gives you better instruments. It does not absolve you from running the experiment.&lt;/p&gt;
&lt;h2 id=&quot;what-should-you-lock-down-before-a-rollout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-ga/#what-should-you-lock-down-before-a-rollout&quot;&gt;&lt;span&gt;What should you lock down before a rollout?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Treat Adaptive Warehouses like a new spend surface. The permission model is still Snowflake RBAC, which is good news for teams that already separate platform ownership from workload usage.&lt;/p&gt;
&lt;p&gt;Grant runtime access 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 reporting_wh &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE analyst_role&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 reporting_wh &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE finops_readonly_role&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 reporting_wh &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE platform_ops_role&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Snowflake says &lt;code&gt;USAGE&lt;/code&gt; lets a role execute queries on a warehouse, &lt;code&gt;MONITOR&lt;/code&gt; lets a role view current and past queries plus usage statistics, and &lt;code&gt;OPERATE&lt;/code&gt; lets a role change warehouse state and abort running queries in the &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/alter-warehouse#access-control-requirements&quot;&gt;ALTER WAREHOUSE access control docs&lt;/a&gt;. Keep &lt;code&gt;MODIFY&lt;/code&gt; away from casual owners, because it allows altering warehouse properties.&lt;/p&gt;
&lt;p&gt;Then add a resource monitor. Snowflake says a resource monitor can suspend a standard warehouse or disable an Adaptive Warehouse when a credit limit is reached in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/resource-monitors&quot;&gt;resource monitor docs&lt;/a&gt;. The word is different because Adaptive Warehouses do not use suspend and resume in the same way.&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;USE&lt;/span&gt; ROLE ACCOUNTADMIN&lt;span class=&quot;token punctuation&quot;&gt;;&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; RESOURCE MONITOR rm_reporting_wh
  &lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; CREDIT_QUOTA &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;
  FREQUENCY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; MONTHLY
  START_TIMESTAMP &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; IMMEDIATELY
  TRIGGERS &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PERCENT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DO&lt;/span&gt; NOTIFY
           &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PERCENT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DO&lt;/span&gt; SUSPEND_IMMEDIATE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; WAREHOUSE reporting_wh
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; RESOURCE_MONITOR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rm_reporting_wh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Snowflake says only &lt;code&gt;ACCOUNTADMIN&lt;/code&gt; can create resource monitors, and only &lt;code&gt;ACCOUNTADMIN&lt;/code&gt; can assign warehouses to resource monitors in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/resource-monitors#creating-a-resource-monitor-with-a-default-schedule&quot;&gt;resource monitor setup docs&lt;/a&gt;. For Adaptive Warehouses, &lt;code&gt;SUSPEND&lt;/code&gt; and &lt;code&gt;SUSPEND_IMMEDIATE&lt;/code&gt; map to disable behavior, and the warehouse can show &lt;code&gt;STATE = DISABLED&lt;/code&gt; with &lt;code&gt;DISABLED_REASONS&lt;/code&gt; listing the monitor in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/resource-monitors#adaptive-warehouses&quot;&gt;Adaptive resource monitor section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My rollout rule: one Adaptive Warehouse, one resource monitor, one owner, one week of query tags. If the workload cannot survive that much discipline, it is already too messy for automatic scaling.&lt;/p&gt;
&lt;h2 id=&quot;when-is-adaptive-compute-the-wrong-call&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-ga/#when-is-adaptive-compute-the-wrong-call&quot;&gt;&lt;span&gt;When is Adaptive Compute the wrong call?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use Adaptive for workloads where static sizing is already making you choose between queue pain and idle spend. Snowflake explicitly lists analytical workloads, data loading pipelines, mixed BI and ETL, and workloads with query sizes ranging from &lt;code&gt;XSMALL&lt;/code&gt; to &lt;code&gt;XLARGE&lt;/code&gt; as good candidates in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#when-to-use-an-adaptive-warehouse&quot;&gt;when to use guidance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Avoid it for three cases. First, primarily HTAP workloads should use standard Gen2 warehouses, according to Snowflake&#39;s &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive#when-to-use-an-adaptive-warehouse&quot;&gt;alternative warehouse guidance&lt;/a&gt;. Second, very low latency dashboards and applications should look at interactive warehouses. Third, high-memory Snowpark or ML workloads on a single node should look at Snowpark-optimized warehouses.&lt;/p&gt;
&lt;p&gt;The most underrated risk is organizational, not technical. Adaptive Compute removes familiar controls, which means the bill owner loses the comfort of a fixed size and gains a stream of per-query charges. That is a better model for agentic SQL and bursty BI, but only if your team already uses &lt;code&gt;QUERY_TAG&lt;/code&gt;, knows who owns each role, and reviews &lt;code&gt;ACCOUNT_USAGE&lt;/code&gt; before the invoice arrives.&lt;/p&gt;
&lt;h2 id=&quot;the-bet-to-make-now&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-ga/#the-bet-to-make-now&quot;&gt;&lt;span&gt;The bet to make now&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Do not convert the estate because Snowflake published a 1.2x benchmark. Convert one noisy AWS warehouse because query-level billing gives you a cleaner argument about who caused the spend.&lt;/p&gt;
&lt;p&gt;Snowflake Adaptive Compute is strongest where your current tuning ritual is guesswork: the BI warehouse that is too small at 9 a.m., too large at noon, and politically impossible to resize. Start there. If Adaptive turns that mess into measurable per-query economics, keep going. If it only makes the bill harder to explain, roll back with one &lt;code&gt;ALTER WAREHOUSE&lt;/code&gt; and enjoy the rare cloud migration with an escape hatch.&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-ga/#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://www.snowflake.com/en/blog/adaptive-compute-generally-available/&quot;&gt;Snowflake Blog: Snowflake Adaptive Compute Is Now Generally Available&lt;/a&gt;&lt;/li&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/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/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/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>Snowflake Iceberg ADLS writes are finally usable</title>
    <link href="https://data-today.net/snowflake/snowflake-iceberg-adls-writes/" />
    <updated>2026-06-15T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-iceberg-adls-writes/</id>
    <content type="html">&lt;p&gt;Azure lakehouse teams just got a less awkward route into Snowflake. Snowflake Iceberg ADLS support is now generally available, which means Snowflake can read and write externally managed Apache Iceberg tables whose files live in Azure Data Lake Storage Gen2. The important number is not a benchmark. It is &lt;strong&gt;1 storage architecture you no longer have to contort&lt;/strong&gt;: ADLS Gen2 can now stay the physical home for externally managed Iceberg tables while Snowflake does the SQL work.&lt;/p&gt;
&lt;p&gt;Snowflake announced the change on June 12, 2026, in its release notes, saying ADLS Gen2 support for Apache Iceberg tables is generally available and works for reading and writing externally managed Iceberg tables on Azure storage. The release also calls out the practical unlock: interoperability with remote catalogs that only use Data Lake Storage, including Unity Catalog hosted on Azure. You can connect through catalog-vended credentials or through an external volume, according to the &lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-06-12-iceberg-azure-dls-external-volumes-ga&quot;&gt;Snowflake release note&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That sounds like plumbing. It is. But plumbing decides whether your migration plan needs a second copy of the lake.&lt;/p&gt;
&lt;h2 id=&quot;what-changed-for-azure-iceberg-tables-on-june-12-2026&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-adls-writes/#what-changed-for-azure-iceberg-tables-on-june-12-2026&quot;&gt;&lt;span&gt;What changed for Azure Iceberg tables on June 12, 2026?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before this release, Azure teams using Iceberg with remote catalogs had an uncomfortable split: Snowflake could participate in Iceberg workflows, but ADLS Gen2 was a rough edge if your catalog and storage architecture were already centered on Azure Data Lake Storage. The June 12 release closes that gap for externally managed Iceberg tables on ADLS Gen2, so Snowflake can read and write against tables where the catalog remains external.&lt;/p&gt;
&lt;p&gt;The two connection paths matter because they imply different ownership models. With catalog-vended credentials, your REST catalog hands Snowflake temporary access to the table files. Snowflake says this mode is supported for externally managed Iceberg tables that use an Iceberg REST catalog, and the table files must be stored in &lt;strong&gt;a single bucket or equivalent storage location per table&lt;/strong&gt;. If the catalog does not provide an expiration time, Snowflake assumes the credentials expire 60 minutes after receipt, per the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-catalog-integration-vended-credentials&quot;&gt;catalog-vended credentials documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The vended-credentials shape is usually cleaner for a platform team. The catalog remains the authority for storage access. Snowflake becomes another engine that asks for short-lived credentials. Here is the key bit of syntax:&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; CATALOG INTEGRATION azure_uc_rest
  CATALOG_SOURCE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ICEBERG_REST
  TABLE_FORMAT &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ICEBERG
  REST_CONFIG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    CATALOG_URI &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://&amp;lt;catalog-endpoint&gt;&#39;&lt;/span&gt;
    ACCESS_DELEGATION_MODE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; VENDED_CREDENTIALS
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  REST_AUTHENTICATION &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;TYPE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BEARER
    BEARER_TOKEN &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;token&gt;&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  ENABLED &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;TRUE&lt;/span&gt;
  REFRESH_INTERVAL_SECONDS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you use an external volume instead, Snowflake stores a named account-level object that points at your storage location. For ADLS Gen2 interoperability, Snowflake tells you to use the &lt;code&gt;dfs.core.windows.net&lt;/code&gt; endpoint, not the Blob endpoint, when you want Snowflake writes to be compatible with remote catalogs that use Data Lake Storage. The &lt;code&gt;STORAGE_BASE_URL&lt;/code&gt; must use the &lt;code&gt;azure://&lt;/code&gt; prefix, according to Snowflake&#39;s &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-external-volume-azure&quot;&gt;external volume for Azure 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;CREATE&lt;/span&gt; EXTERNAL VOLUME exvol_adls_iceberg
  STORAGE_LOCATIONS &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 punctuation&quot;&gt;(&lt;/span&gt;
      NAME &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;prod-adls-eastus&#39;&lt;/span&gt;
      STORAGE_PROVIDER &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;AZURE&#39;&lt;/span&gt;
      STORAGE_BASE_URL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;azure://acct.dfs.core.windows.net/iceberg/&#39;&lt;/span&gt;
      AZURE_TENANT_ID &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;tenant-id&gt;&#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;
  ALLOW_WRITES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt; EXTERNAL VOLUME exvol_adls_iceberg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; SYSTEM$VERIFY_EXTERNAL_VOLUME&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;exvol_adls_iceberg&#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;One vendor-honest footnote: the release note marks ADLS Gen2 support generally available, while the Azure external-volume page still carries a preview callout around Data Lake Storage Gen2 configuration. For a regulated production rollout, treat the June 12 release note as the feature milestone, then confirm your exact account, region, private connectivity, and support posture with Snowflake before you make it the only write path.&lt;/p&gt;
&lt;h2 id=&quot;how-does-snowflake-actually-write-to-an-externally-managed-table&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-adls-writes/#how-does-snowflake-actually-write-to-an-externally-managed-table&quot;&gt;&lt;span&gt;How does Snowflake actually write to an externally managed table?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake writes by linking its table object to the table in your remote Iceberg REST catalog. When you change the table in Snowflake, Snowflake commits the same change to the remote catalog before it updates the table in Snowflake. That commit ordering is the important behavior, because your catalog remains the shared truth for Spark, Databricks, Trino, Snowflake, and whatever engine shows up next quarter.&lt;/p&gt;
&lt;p&gt;Snowflake supports two shapes. A catalog-linked database automatically syncs namespaces and tables from the remote catalog. A standard Snowflake database requires the remote table to exist first, then you create a Snowflake Iceberg table object pointing at it. Snowflake&#39;s write-support docs say catalog-linked databases can create new Iceberg tables in Snowflake and in the external catalog at the same time, while standard databases need the table created in the remote catalog first via the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-externally-managed-writes&quot;&gt;externally managed write workflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For an Azure Unity Catalog style setup, the catalog-linked database is the more natural interface. It gives Snowflake a database view over a remote catalog, with automatic discovery every 30 seconds by default.&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 keyword&quot;&gt;DATABASE&lt;/span&gt; lakehouse_prod
  LINKED_CATALOG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    CATALOG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;azure_uc_rest&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ALLOWED_NAMESPACES &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 string&quot;&gt;&#39;gold&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;silver&#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;
    ALLOWED_WRITE_OPERATIONS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ALL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SYNC_INTERVAL_SECONDS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  CATALOG_CASE_SENSITIVITY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; CASE_INSENSITIVE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The setting you should stare at is &lt;code&gt;ALLOWED_WRITE_OPERATIONS&lt;/code&gt;. Snowflake&#39;s catalog-linked database syntax makes it &lt;code&gt;ALL&lt;/code&gt; by default. That is convenient in a demo and too generous for most enterprises. When writes are enabled, table drops propagate to the remote catalog and remove the table and data from both systems, according to the &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-database-catalog-linked&quot;&gt;CREATE DATABASE catalog-linked reference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A safer rollout starts read-only, then opens writes namespace by namespace:&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 keyword&quot;&gt;DATABASE&lt;/span&gt; lakehouse_ro
  LINKED_CATALOG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    CATALOG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;azure_uc_rest&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ALLOWED_NAMESPACES &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 string&quot;&gt;&#39;gold&#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;
    ALLOWED_WRITE_OPERATIONS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NONE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SYNC_INTERVAL_SECONDS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;900&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;Once writable, Snowflake supports the familiar DML surface: &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, &lt;code&gt;MERGE&lt;/code&gt;, &lt;code&gt;TRUNCATE TABLE&lt;/code&gt;, and &lt;code&gt;COPY INTO &amp;lt;table&amp;gt;&lt;/code&gt;. It also supports streams for CDC into an externally managed Iceberg table. That is where this feature stops being a catalog checkbox and starts becoming a pipeline primitive.&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;MERGE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; lakehouse_prod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gold&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customer_iceberg t
&lt;span class=&quot;token keyword&quot;&gt;USING&lt;/span&gt; staging_customer_delta s
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customer_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customer_id
&lt;span class=&quot;token keyword&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;MATCHED&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&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; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;MATCHED&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INSERT&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 keyword&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;customer_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;status&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;If your source is an externally managed Iceberg table, Snowflake requires &lt;code&gt;INSERT_ONLY = TRUE&lt;/code&gt; when you create the stream. That constraint is easy to miss during a CDC migration, and it is exactly the kind of small syntax rule that turns a Friday cutover into a Monday incident.&lt;/p&gt;
&lt;h2 id=&quot;how-will-this-show-up-on-the-snowflake-bill&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-adls-writes/#how-will-this-show-up-on-the-snowflake-bill&quot;&gt;&lt;span&gt;How will this show up on the Snowflake bill?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is no new magic meter called ADLS. The bill lands in the places Snowflake already uses for Iceberg: virtual warehouse compute, cloud services, automated refresh and data registration, and possibly external Azure storage or egress from your cloud provider.&lt;/p&gt;
&lt;p&gt;Snowflake&#39;s Iceberg billing docs say Snowflake bills virtual warehouse compute and cloud services when you work with Iceberg tables, and does not bill your account for Iceberg table storage because the files live in your cloud storage. Snowflake still exposes &lt;code&gt;ACTIVE_BYTES&lt;/code&gt; for Iceberg tables in storage metrics, which is useful for chargeback even though Azure bills the storage, as summarized in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg.html#billing&quot;&gt;Apache Iceberg tables billing section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The polling knob is the first FinOps control. &lt;code&gt;REFRESH_INTERVAL_SECONDS&lt;/code&gt; on a REST catalog integration supports values from &lt;strong&gt;30 to 86,400 seconds&lt;/strong&gt;, with 30 seconds as the default. Catalog-linked databases also use a 30 second default sync interval and the same 30 to 86,400 second range. If you set every catalog to poll every 30 seconds because that is the default, you are choosing freshness before you have measured whether the business needs it.&lt;/p&gt;
&lt;p&gt;The chart below shows the operating numbers worth putting in your migration runbook: 30 seconds default polling, 86,400 seconds maximum polling, and 10,800 seconds, meaning 180 minutes, as the documented maximum latency for &lt;code&gt;PIPE_USAGE_HISTORY&lt;/code&gt; data.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-iceberg-adls-writes-fig-polling-cost-knobs.png&quot; alt=&quot;Snowflake Iceberg ADLS operating chart showing 30 seconds default polling, 86,400 seconds maximum polling, and 10,800 seconds Account Usage latency ceiling.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Snowflake documents 30 seconds as the default polling interval, 86,400 seconds as the maximum polling interval, and 10,800 seconds, or 180 minutes, as the Account Usage latency ceiling for PIPE_USAGE_HISTORY.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Use the Account Usage views immediately. &lt;code&gt;PIPE_USAGE_HISTORY&lt;/code&gt; tracks credits used for Iceberg automated refresh for the last 365 days, and Snowflake says the view can lag by up to 180 minutes. It also states that Snowflake does not bill Snowpipe file charges for Iceberg automated refresh, which keeps the charge model cleaner than external-table notification billing.&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;
  pipe_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 string&quot;&gt;&#39;day&#39;&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; refresh_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;pipe_usage_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;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 operator&quot;&gt;AND&lt;/span&gt; pipe_name &lt;span class=&quot;token operator&quot;&gt;ILIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;%customer_iceberg%&#39;&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;2&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DESC&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 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;Catalog-linked databases have their own view. &lt;code&gt;CATALOG_LINKED_DATABASE_USAGE_HISTORY&lt;/code&gt; keeps 12 months of usage and splits &lt;code&gt;CREDITS_USED_COMPUTE&lt;/code&gt;, &lt;code&gt;CREDITS_USED_CLOUD_SERVICES&lt;/code&gt;, and &lt;code&gt;CREDITS_USED&lt;/code&gt;. Snowflake says table creation uses compute through auto refresh, while automatic table discovery, schema creation or deletion, and table deletion use cloud services.&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;
  database_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 string&quot;&gt;&#39;day&#39;&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_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 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; billed_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;catalog_linked_database_usage_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;30&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;2&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &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;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;Concrete behavior&lt;/th&gt;
&lt;th&gt;Cost or control signal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Catalog-vended credentials&lt;/td&gt;
&lt;td&gt;No &lt;code&gt;EXTERNAL_VOLUME&lt;/code&gt; parameter on the table when the catalog integration uses &lt;code&gt;VENDED_CREDENTIALS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Credential expiration must be supplied by the catalog, otherwise Snowflake assumes 60 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;External volume on ADLS Gen2&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;azure://account.dfs.core.windows.net/container/&lt;/code&gt; for Data Lake Storage&lt;/td&gt;
&lt;td&gt;Needs &lt;code&gt;CREATE EXTERNAL VOLUME&lt;/code&gt; at account level and Azure storage permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catalog-linked database&lt;/td&gt;
&lt;td&gt;Sync interval defaults to 30 seconds and can rise to 86,400 seconds&lt;/td&gt;
&lt;td&gt;Track spend in &lt;code&gt;CATALOG_LINKED_DATABASE_USAGE_HISTORY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automated refresh&lt;/td&gt;
&lt;td&gt;Credits appear through the Snowpipe usage view&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PIPE_USAGE_HISTORY&lt;/code&gt; can lag by up to 180 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is the same discipline behind &lt;a href=&quot;https://data-today.net/snowflake/snowflake-warehouse-sizing/&quot;&gt;Snowflake warehouse sizing&lt;/a&gt;: do not start with the biggest knob and call it architecture.&lt;/p&gt;
&lt;h2 id=&quot;what-should-an-azure-platform-team-do-first&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-adls-writes/#what-should-an-azure-platform-team-do-first&quot;&gt;&lt;span&gt;What should an Azure platform team do first?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start with a read-only mirror of the catalog. Use &lt;code&gt;ALLOWED_NAMESPACES&lt;/code&gt; so Snowflake does not discover your entire lake on day 1, set &lt;code&gt;ALLOWED_WRITE_OPERATIONS = NONE&lt;/code&gt;, and choose a sync interval that matches the table&#39;s change rate. For most BI and model-feature tables, 300 or 900 seconds is a saner starting point than 30 seconds.&lt;/p&gt;
&lt;p&gt;Then give access through database roles inside the catalog-linked database. Snowflake says catalog-linked databases support database roles, masking policies, and tags, but do not sync remote catalog access control for users or roles. Translation: your Snowflake RBAC model remains your problem. If your governance design assumes Unity Catalog permissions magically follow the data into Snowflake, fix that assumption before the pilot.&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 keyword&quot;&gt;DATABASE&lt;/span&gt; ROLE lakehouse_prod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readers&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; lakehouse_prod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gold
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DATABASE&lt;/span&gt; ROLE lakehouse_prod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readers&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; ICEBERG &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; lakehouse_prod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gold
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DATABASE&lt;/span&gt; ROLE lakehouse_prod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readers&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;DATABASE&lt;/span&gt; ROLE lakehouse_prod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readers &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE analyst_ro&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For writes, create a separate role and keep table drops out of casual hands. The dangerous part is not &lt;code&gt;MERGE&lt;/code&gt;. The dangerous part is a writable linked catalog where &lt;code&gt;DROP ICEBERG TABLE&lt;/code&gt; is allowed and the remote catalog follows orders.&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 iceberg_writer&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; lakehouse_prod &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE iceberg_writer&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; lakehouse_prod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;silver &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE iceberg_writer&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;INSERT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&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; ICEBERG &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; lakehouse_prod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;silver
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE iceberg_writer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also test the limits before you promise a platform standard. Snowflake lists several unsupported or constrained areas for externally managed writes: multi-statement transactions are not supported, Azure server-side encryption for Azure external volumes is not supported for this write path, &lt;code&gt;uuid&lt;/code&gt; and &lt;code&gt;fixed(L)&lt;/code&gt; writes are not supported, sharing with a listing is not supported, and equality delete files are not supported. Snowflake supports Iceberg version 2 and version 3 for externally managed writes, which is good, but it does not remove the need for table-maintenance ownership.&lt;/p&gt;
&lt;p&gt;If you are still deciding whether to make Iceberg your Snowflake boundary, read our guide on &lt;a href=&quot;https://data-today.net/snowflake/snowflake-iceberg-tables/&quot;&gt;whether to put your data lake in Snowflake Iceberg tables&lt;/a&gt; before you let a single GA badge settle the architecture.&lt;/p&gt;
&lt;h2 id=&quot;when-is-snowflake-iceberg-adls-the-wrong-choice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-adls-writes/#when-is-snowflake-iceberg-adls-the-wrong-choice&quot;&gt;&lt;span&gt;When is Snowflake Iceberg ADLS the wrong choice?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Do not use it to avoid making a warehouse decision. If all consumers are in Snowflake, standard Snowflake tables or Snowflake-managed Iceberg tables may still give you simpler operations. Externally managed Iceberg earns its keep when other engines must read or write the same tables, when the catalog is already a platform contract, or when Azure storage ownership is politically and financially fixed.&lt;/p&gt;
&lt;p&gt;Do not use it as a dumping ground for every namespace. The default 30 second discovery and refresh posture is fine for a demo namespace with 12 tables. It is a different animal when pointed at a busy catalog with hundreds or thousands of tables, frequent commits, and platform teams that only check Account Usage once a month.&lt;/p&gt;
&lt;p&gt;Do use it for a narrow Azure migration slice: one remote catalog, two namespaces, 5 to 10 critical tables, explicit &lt;code&gt;SYNC_INTERVAL_SECONDS&lt;/code&gt;, read-only first, write role second, and a daily spend query. If that sounds boring, good. Boring is how lakehouse migrations survive contact with finance.&lt;/p&gt;
&lt;p&gt;The feature does not make Snowflake the owner of your lake. It makes Snowflake a better citizen in an Azure Iceberg lakehouse. That is the right level of ambition.&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-adls-writes/#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/release-notes/2026/other/2026-06-12-iceberg-azure-dls-external-volumes-ga&quot;&gt;Snowflake Documentation: Jun 12, 2026, Apache Iceberg tables Azure Data Lake Storage Gen2 support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-external-volume-azure&quot;&gt;Snowflake Documentation: Configure an external volume for Azure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-catalog-integration-vended-credentials&quot;&gt;Snowflake Documentation: Use catalog-vended credentials 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-externally-managed-writes&quot;&gt;Snowflake Documentation: Write support for externally managed 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.html&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/sql-reference/sql/create-external-volume&quot;&gt;Snowflake Documentation: CREATE EXTERNAL VOLUME&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-catalog-integration-rest&quot;&gt;Snowflake Documentation: CREATE CATALOG INTEGRATION for Apache Iceberg REST&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-database-catalog-linked&quot;&gt;Snowflake Documentation: CREATE DATABASE catalog-linked&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/pipe_usage_history&quot;&gt;Snowflake Documentation: PIPE_USAGE_HISTORY view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/catalog_linked_database_usage_history&quot;&gt;Snowflake Documentation: CATALOG_LINKED_DATABASE_USAGE_HISTORY view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/service-types&quot;&gt;Snowflake Documentation: Service types&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake Hybrid Tables get faster without request fees</title>
    <link href="https://data-today.net/snowflake/snowflake-hybrid-tables-speed/" />
    <updated>2026-06-15T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-hybrid-tables-speed/</id>
    <content type="html">&lt;p&gt;Snowflake Hybrid Tables used to sit in an awkward box: promising enough to simplify app architectures, but not quite boring enough for the team that gets paged when an OLTP-ish workload misbehaves inside a warehouse. The new Snowflake Hybrid Tables update changes that calculus, at least for a specific class of workloads: repetitive point reads and small writes that look more like application state than BI.&lt;/p&gt;
&lt;p&gt;The headline is simple: Snowflake says its public preview operational query optimization can deliver &lt;strong&gt;up to 8x better throughput&lt;/strong&gt; on a Gen2 warehouse for a 100 percent read Yahoo Cloud Serving Benchmark workload, while the March 2026 billing change removed separate hybrid table request credits. That combination matters more than either claim alone. Faster point lookups are nice. Faster point lookups without a separate request meter are the part your FinOps reviewer will notice.&lt;/p&gt;
&lt;p&gt;This is not Snowflake turning into Postgres. Hybrid Tables are still Snowflake tables, with Snowflake constraints, warehouses, account usage views, and Snowflake lock-in. But for workflow state, metadata, recommendation serving, entitlements, and agent state where the alternative is another database plus another sync pipeline, the feature deserves a fresh benchmark.&lt;/p&gt;
&lt;h2 id=&quot;what-changed-in-snowflake-hybrid-tables-exactly&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-hybrid-tables-speed/#what-changed-in-snowflake-hybrid-tables-exactly&quot;&gt;&lt;span&gt;What changed in Snowflake Hybrid Tables, exactly?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake shipped three related changes around Hybrid Tables: a preview optimization for operational queries, optimized bulk loading, and simplified pricing. The operational query work is the most important technical change. Snowflake describes operational queries as hybrid table statements that select or modify a small number of rows and execute in less than 100 ms, and says the optimization applies when the same SQL structure runs repeatedly, the query touches only hybrid tables, and the result is no larger than 100 KB in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/hybrid-tables-operational-query-performance&quot;&gt;operational query optimization docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Enablement is warehouse-level, not table-level. That is the right shape. You can isolate a benchmark warehouse, turn the preview on, and avoid changing application DDL while you measure.&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; WAREHOUSE ht_app_wh
  WAREHOUSE_SIZE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; XSMALL
  AUTO_SUSPEND &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;
  AUTO_RESUME &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;TRUE&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 ht_app_wh
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; ENABLE_USE_STABLE_PATH &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The feature is still a preview as of June 15, 2026, and that is not a footnote. Snowflake says cloud services compute incurred for queries on the optimized path is not currently billed, but that this will change when the feature reaches general availability. If you benchmark now and ship a production design on preview economics, write that assumption down in your cost model in red ink.&lt;/p&gt;
&lt;p&gt;The chart below shows the reported relative gains Snowflake published for the update. The clean read: operational point lookup throughput is the flagship number, while bulk load improvements are the practical unlock for backfills and state syncs.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-hybrid-tables-speed-fig-hybrid-table-gains.png&quot; alt=&quot;Bar chart of Snowflake Hybrid Tables gains showing point lookup throughput at 8x, bulk load speed at 10x, and bulk load cost efficiency at 10x.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Snowflake reported up to 8x point lookup throughput, 10x faster bulk loads, and 10x lower bulk load cost for Hybrid Tables in internal benchmarks.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Snowflake reports &lt;strong&gt;8x&lt;/strong&gt; better point lookup throughput in the YCSB read benchmark, and &lt;strong&gt;10x&lt;/strong&gt; faster bulk loads at &lt;strong&gt;10x&lt;/strong&gt; lower cost for a 50 GB load into Hybrid Tables in its June 10, 2026 blog post, &lt;a href=&quot;https://www.snowflake.com/en/blog/hybrid-tables-performance-improvements/&quot;&gt;Hybrid Tables Just Got Up to 8x Faster&lt;/a&gt;. Treat those as vendor benchmarks, not a substitute for your own concurrency test.&lt;/p&gt;
&lt;p&gt;Bulk loading also got more useful. Snowflake says optimized bulk loading supports CTAS, COPY, and all variants of INSERT except INSERT ALL, including loads into tables that already contain data, in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-hybrid-best-practices&quot;&gt;Hybrid Tables best practices guide&lt;/a&gt;. That is the difference between a feature you can demo and a feature you can backfill on a Tuesday.&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; HYBRID &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; app_state &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  entity_id NUMBER &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  state_version NUMBER &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  payload VARIANT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updated_at TIMESTAMP_NTZ &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &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;entity_id&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;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; app_state
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; entity_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; state_version&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updated_at
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; staging_app_state&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is one catch in that CTAS path. Hybrid Tables require an explicit primary key, and Snowflake says CTAS for a hybrid table cannot infer the schema from the SELECT. If you need foreign keys, Snowflake says CTAS does not support them, so use COPY or INSERT INTO SELECT instead.&lt;/p&gt;
&lt;h2 id=&quot;how-does-the-optimized-path-actually-decide-what-to-accelerate&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-hybrid-tables-speed/#how-does-the-optimized-path-actually-decide-what-to-accelerate&quot;&gt;&lt;span&gt;How does the optimized path actually decide what to accelerate?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The preview is not a magic turbo button for any query that mentions a Hybrid Table. Snowflake says optimization is limited to statements that interact only with hybrid tables. If you join a Hybrid Table to a standard Snowflake table, the query still works, but it does not get this optimization.&lt;/p&gt;
&lt;p&gt;The sweet spot looks like application code with stable prepared statements:&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; &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updated_at
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; app_state
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; entity_id &lt;span class=&quot;token operator&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 question mark matters. Snowflake says parameterized statements with the same structure but different bind values are eligible after repeated execution. If your application injects random comments, builds bespoke SQL strings for every request, or adds ornamental CTEs to point lookups, you are making the optimizer’s job harder for no prize.&lt;/p&gt;
&lt;p&gt;Supported statement patterns include SELECT, INSERT, UPDATE, and DELETE, with WHERE comparisons using operators such as equals, less than, and greater than. ORDER BY with or without LIMIT is eligible. The optimized join patterns are narrower: primary key to primary key joins, foreign key to foreign key joins, and index nested loop joins on a primary key.&lt;/p&gt;
&lt;p&gt;That constraint is useful. It tells you what to migrate first.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload pattern&lt;/th&gt;
&lt;th&gt;Good fit for the preview?&lt;/th&gt;
&lt;th&gt;Concrete behavior to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Point lookup by primary key&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Result must stay at or below 100 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Small single-row update&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Preview supports single-statement transactions with AUTOCOMMIT enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Join to standard fact table&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Optimization is limited to queries that touch only Hybrid Tables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GROUP BY over app state&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;GROUP BY works, but does not benefit from the preview optimization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-statement transaction&lt;/td&gt;
&lt;td&gt;No for preview&lt;/td&gt;
&lt;td&gt;Snowflake documents only single-statement transactions for this preview&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For a builder, this means you should not start by moving your analytical model into Hybrid Tables. Start with a hot state table that has a primary key, predictable predicates, and a pile of repeated calls from a service. If you are also testing Gen2 warehouses, read our guide to &lt;a href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/&quot;&gt;Gen2 warehouse trade-offs&lt;/a&gt; before you compare old and new numbers.&lt;/p&gt;
&lt;h2 id=&quot;how-is-it-billed-now-and-what-should-finops-watch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-hybrid-tables-speed/#how-is-it-billed-now-and-what-should-finops-watch&quot;&gt;&lt;span&gt;How is it billed now, and what should FinOps watch?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The billing story got much simpler on March 1, 2026. Snowflake’s release note says hybrid table requests are no longer charged as a separate billing category, replacing the old three-part model with two charges: hybrid table storage and virtual warehouse compute in the &lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-03-02-hybrid-tables-pricing&quot;&gt;simplified pricing release note&lt;/a&gt;. Snowflake followed on March 16, 2026 by disabling new metering events for hybrid table requests in HYBRID_TABLE_USAGE_HISTORY and METERING_DAILY_HISTORY.&lt;/p&gt;
&lt;p&gt;That removes one nasty surprise from the bill. It does not make Hybrid Tables cheap by default.&lt;/p&gt;
&lt;p&gt;Hybrid table storage is row-store storage, and Snowflake says it is more expensive than traditional Snowflake storage. The current data copy in columnar object storage is not billed as a separate copy, while historical Time Travel data is billed at standard storage rates in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-hybrid-cost&quot;&gt;cost evaluation docs&lt;/a&gt;. The Snowflake Service Consumption Table lists region-specific hybrid storage prices, including &lt;strong&gt;$0.34 per GB per month&lt;/strong&gt; for AWS US East at the time of this guide.&lt;/p&gt;
&lt;p&gt;Use account usage views before debating architecture in a meeting.&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;
  usage_date&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;hybrid_table_storage_bytes &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;2&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; hybrid_table_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;storage_bytes &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;2&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; total_storage_gb
&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;storage_usage
&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_date &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;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Warehouse compute is the other meter. Queries against Hybrid Tables run on virtual warehouses, with the same warehouse consumption model as standard table queries. The pricing risk is therefore familiar: a chatty application can keep an X-Small warehouse warm all day, and low-latency settings often mean lower AUTO_SUSPEND values are not enough by themselves.&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 string&quot;&gt;&#39;day&#39;&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; 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;HT_APP_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 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;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;2&lt;/span&gt; &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;Also check that request metering really stopped in your account. Historical rows remain available, so query after the cutoff.&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; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;
&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;hybrid_table_usage_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; &lt;span class=&quot;token string&quot;&gt;&#39;2026-03-16&#39;&lt;/span&gt;::TIMESTAMP_LTZ
&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 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;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If that returns new request usage rows after March 16, open a ticket before you ship assumptions into a forecast. If it returns nothing, good. Your cost argument moves to storage footprint, warehouse uptime, and whether the architecture deletes another system.&lt;/p&gt;
&lt;h2 id=&quot;what-limits-can-still-wreck-a-production-rollout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-hybrid-tables-speed/#what-limits-can-still-wreck-a-production-rollout&quot;&gt;&lt;span&gt;What limits can still wreck a production rollout?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most important limit is throughput per database. Snowflake currently documents approximately &lt;strong&gt;16,000 operations per second per Snowflake database&lt;/strong&gt; for a balanced workload of 80 percent point reads and 20 percent point writes, with throttling visible through AGGREGATE_QUERY_HISTORY in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-hybrid-limitations&quot;&gt;Hybrid Tables limitations page&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;SELECT&lt;/span&gt;
  interval_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;
  &lt;span class=&quot;token function&quot;&gt;SUM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;calls&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; calls&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;hybrid_table_requests_throttled_count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; throttled_requests
&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;aggregate_query_history
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; interval_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;hour&#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;6&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; warehouse_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;HT_APP_WH&#39;&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; interval_start_time &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;Storage has a hard planning boundary too: Snowflake documents a &lt;strong&gt;2 TB hybrid storage quota per Snowflake database&lt;/strong&gt;. That limit applies to active hybrid table data in the row store. If you blow through it, writes that add data can be blocked until you remove data or tables. Deleting rows may take hours to reclaim space because background compaction has to run, while DROP or TRUNCATE can reclaim space in seconds.&lt;/p&gt;
&lt;p&gt;Region support is another practical gate. Hybrid Tables are generally available in commercial AWS and Microsoft Azure regions, but Snowflake says they are not available in Google Cloud, U.S. SnowGov Regions, or trial accounts. If your enterprise standard is GCP Snowflake, this guide is mostly a future-looking planning note.&lt;/p&gt;
&lt;p&gt;There are also feature gaps that matter to data engineers. Hybrid Tables do not support streams, dynamic tables, materialized views, replication, data sharing, Snowpipe, Snowpipe Streaming API, clustering keys, Search Optimization Service, Query Acceleration Service, Fail-safe, or UNDROP for the hybrid tables themselves. That list is not trivia. It tells you Hybrid Tables are an application-serving and state-management tool, not a drop-in replacement for your pipeline substrate.&lt;/p&gt;
&lt;p&gt;Constraints are stricter than standard Snowflake tables. A Hybrid Table must have a primary key, and primary key, unique, and foreign key constraints are enforced. That is good for app correctness. It also means bad backfill rows fail instead of quietly becoming tomorrow’s data quality incident.&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; HYBRID &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; workflow_run &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  run_id NUMBER &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  pipeline_name &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  started_at TIMESTAMP_NTZ &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  finished_at TIMESTAMP_NTZ&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &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;run_id&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;INDEX&lt;/span&gt; idx_pipeline_status &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pipeline_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;status&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;Watch index width. Snowflake warns that wide indexed columns can fail during loads because row-based storage imposes a limit on the size of data and metadata stored per record. VARIANT can live in the table, but not as a primary key or indexed column.&lt;/p&gt;
&lt;h2 id=&quot;who-should-try-it-first-and-who-should-wait&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-hybrid-tables-speed/#who-should-try-it-first-and-who-should-wait&quot;&gt;&lt;span&gt;Who should try it first, and who should wait?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Try Snowflake Hybrid Tables now if your current architecture has one small operational database whose main job is to sit next to Snowflake and remember things Snowflake already understands: job state, recommendation IDs, customer entitlements, agent checkpoints, application configuration, or workflow status. That external database has a bill, a security model, backups, alerts, schema migrations, and a sync path. Consolidation is a legitimate performance feature when it deletes all of that.&lt;/p&gt;
&lt;p&gt;Do not start with your highest-volume customer-facing OLTP system. If the service has strict single-digit millisecond SLOs, multi-region failover requirements, heavy multi-statement transactions, or expects Postgres-compatible behavior, Snowflake is still not pretending to be that database. Good. You should not pretend either.&lt;/p&gt;
&lt;p&gt;A sane rollout looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pick one table under 100 GB with a primary-key access pattern.&lt;/li&gt;
&lt;li&gt;Put it in a dedicated database so the 16,000 ops per second quota is easy to reason about.&lt;/li&gt;
&lt;li&gt;Use a dedicated X-Small or multi-cluster warehouse, not your BI warehouse.&lt;/li&gt;
&lt;li&gt;Enable &lt;code&gt;ENABLE_USE_STABLE_PATH&lt;/code&gt; only on the test warehouse first.&lt;/li&gt;
&lt;li&gt;Benchmark with bind variables, warm the workload for a few minutes, and track throttling in AGGREGATE_QUERY_HISTORY.&lt;/li&gt;
&lt;li&gt;Compare the full cost against the database and pipeline you can retire, not against warehouse credits alone.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Privileges need attention because Snowflake documentation is in transition. The current command reference lists CREATE TABLE on the schema as the required privilege and notes no separate CREATE HYBRID TABLE privilege, while Snowflake’s 2026_02 behavior change announcement says CREATE HYBRID TABLE becomes a new separate privilege for roles that create new Hybrid Tables in the &lt;a href=&quot;https://docs.snowflake.com/en/release-notes/bcr-bundles/2026_02/bcr-2157&quot;&gt;behavior change note&lt;/a&gt;. The safest enterprise move is to grant narrowly and verify bundle behavior in your account.&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; &lt;span class=&quot;token keyword&quot;&gt;DATABASE&lt;/span&gt; app_db &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE app_state_owner&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; app_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE app_state_owner&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; &lt;span class=&quot;token keyword&quot;&gt;TABLE&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; app_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE app_state_owner&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 punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&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; app_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE app_service_role&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your account requires the new privilege, add it to the owner role and keep it away from broad analyst 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; HYBRID &lt;span class=&quot;token keyword&quot;&gt;TABLE&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; app_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE app_state_owner&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The lock-in trade is real. Hybrid Tables make Snowflake more attractive as an application data plane, but they also move operational state into Snowflake-specific DDL, quotas, and observability. That is worth it when the state mostly serves Snowflake-adjacent workflows. It is much harder to justify when Snowflake is just the third system in a request path.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-practical-call&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-hybrid-tables-speed/#what-is-the-practical-call&quot;&gt;&lt;span&gt;What is the practical call?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Benchmark the workloads you previously rejected because Hybrid Tables were too slow or too weird to bill. The new performance path and request-fee removal are enough to reopen that spreadsheet.&lt;/p&gt;
&lt;p&gt;But be precise. This is not a blanket migration story. It is a narrow, useful answer to a common enterprise mess: too many small operational databases orbiting the warehouse like space junk.&lt;/p&gt;
&lt;p&gt;If Snowflake Hybrid Tables let you delete one of those databases, they are probably worth the test. If they only let you brag that your warehouse can do OLTP now, congratulations on finding the expensive version of a familiar database.&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-hybrid-tables-speed/#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://www.snowflake.com/en/blog/hybrid-tables-performance-improvements/&quot;&gt;Snowflake Blog: Hybrid Tables Just Got Up to 8x Faster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/hybrid-tables-operational-query-performance&quot;&gt;Snowflake Documentation: Performance improvements for operational queries on hybrid tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-hybrid-create&quot;&gt;Snowflake Documentation: Create hybrid tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-hybrid-table&quot;&gt;Snowflake Documentation: CREATE HYBRID TABLE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-hybrid-best-practices&quot;&gt;Snowflake Documentation: Best practices for hybrid tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-hybrid-limitations&quot;&gt;Snowflake Documentation: Limitations and unsupported features for hybrid tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-hybrid-cost&quot;&gt;Snowflake Documentation: Evaluate cost for hybrid tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-03-02-hybrid-tables-pricing&quot;&gt;Snowflake Documentation: Mar 02, 2026, Simplified pricing for hybrid tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/other/2026-03-16-hybrid-tables-metering-disabled&quot;&gt;Snowflake Documentation: Mar 16, 2026, Metering disabled for hybrid table requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/release-notes/bcr-bundles/2026_02/bcr-2157&quot;&gt;Snowflake Documentation: New CREATE HYBRID TABLE privilege&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.snowflake.com/legal-files/CreditConsumptionTable.pdf&quot;&gt;Snowflake Legal: Service Consumption Table&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>ICEBERG_MERGE_ON_READ_BEHAVIOR changes Iceberg DML</title>
    <link href="https://data-today.net/snowflake/snowflake-iceberg-merge-read/" />
    <updated>2026-06-08T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-iceberg-merge-read/</id>
    <content type="html">&lt;p&gt;Snowflake just turned an Iceberg implementation detail into a bill-owner decision.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ICEBERG_MERGE_ON_READ_BEHAVIOR&lt;/code&gt; is the new general availability object parameter that controls whether Snowflake uses merge-on-read or copy-on-write for Iceberg &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, and &lt;code&gt;MERGE&lt;/code&gt;. The key number is simple: under the default &lt;code&gt;AUTO&lt;/code&gt; setting, &lt;strong&gt;3 of 4 table cases use merge-on-read&lt;/strong&gt;, while Snowflake-managed Iceberg v2 tables stay on copy-on-write unless you explicitly opt in.&lt;/p&gt;
&lt;p&gt;That sounds small. It is not. For lakehouse teams, row-level DML is where the open-table dream usually meets the invoice. Copy-on-write rewrites whole data files. Merge-on-read writes delete files alongside the data and makes readers reconcile them later. One mode spends more during writes. The other can push work into reads and compaction. Snowflake&#39;s new parameter matters because it lets you choose that trade-off at the account, database, schema, or table level instead of letting it hide behind a legacy boolean.&lt;/p&gt;
&lt;p&gt;If you are still sorting out where Iceberg belongs in your platform, start with our guide to &lt;a href=&quot;https://data-today.net/snowflake/snowflake-iceberg-tables/&quot;&gt;putting your data lake in Snowflake Iceberg tables&lt;/a&gt;. This one is narrower: how this new switch works, how to audit it, and where it can move credits.&lt;/p&gt;
&lt;h2 id=&quot;what-did-snowflake-actually-ship-for-iceberg-dml&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-merge-read/#what-did-snowflake-actually-ship-for-iceberg-dml&quot;&gt;&lt;span&gt;What did Snowflake actually ship for Iceberg DML?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake added a string parameter, &lt;code&gt;ICEBERG_MERGE_ON_READ_BEHAVIOR&lt;/code&gt;, with three values: &lt;code&gt;AUTO&lt;/code&gt;, &lt;code&gt;ENABLED&lt;/code&gt;, and &lt;code&gt;DISABLED&lt;/code&gt;. The 10.20 release notes say the parameter controls how Snowflake performs row-level updates on Apache Iceberg tables, specifically &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, and &lt;code&gt;MERGE&lt;/code&gt;, by choosing between merge-on-read and copy-on-write in &lt;a href=&quot;https://docs.snowflake.com/en/release-notes/2026/10_20&quot;&gt;Snowflake-issued DML&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The default is &lt;code&gt;AUTO&lt;/code&gt;. In that mode, Snowflake checks two things: the Iceberg format version and whether the table is Snowflake-managed or externally managed. Snowflake-managed v2 tables use copy-on-write. Snowflake-managed v3 tables use merge-on-read. Externally managed v2 and v3 tables use merge-on-read.&lt;/p&gt;
&lt;p&gt;That gives you the 3 to 1 split shown below.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-iceberg-merge-read-fig-auto-mode-matrix.png&quot; alt=&quot;Under ICEBERG_MERGE_ON_READ_BEHAVIOR AUTO, 3 of 4 Iceberg table cases use merge-on-read and 1 of 4 uses copy-on-write.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Snowflake&#39;s AUTO matrix has 3 Iceberg table cases using merge-on-read and 1 case using copy-on-write.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Snowflake&#39;s docs spell out the matrix in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-manage&quot;&gt;row-level deletes guide&lt;/a&gt;. The vendor-safe read is obvious: &lt;code&gt;AUTO&lt;/code&gt; protects Snowflake-managed v2 tables because external readers might not support v2 positional delete files. The builder read is sharper: if you want merge-on-read on Snowflake-managed v2, you must say so.&lt;/p&gt;
&lt;p&gt;Here is the minimum table-level change:&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; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;events
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; ICEBERG_MERGE_ON_READ_BEHAVIOR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ENABLED&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here is the safer default pattern for a database with mixed tables:&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; &lt;span class=&quot;token keyword&quot;&gt;DATABASE&lt;/span&gt; lake_db
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; ICEBERG_MERGE_ON_READ_BEHAVIOR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;AUTO&#39;&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; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;hot_events
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; ICEBERG_MERGE_ON_READ_BEHAVIOR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ENABLED&#39;&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; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;reader_sensitive_events
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; ICEBERG_MERGE_ON_READ_BEHAVIOR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;DISABLED&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The parameter is case-insensitive, and the most specific setting wins. A table setting beats a schema setting, which beats a database setting, which beats the account setting. Snowflake documents the same syntax on &lt;code&gt;CREATE ICEBERG TABLE&lt;/code&gt;, where the parameter defaults to &lt;code&gt;AUTO&lt;/code&gt; and can be set when the table is created in &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table-snowflake&quot;&gt;Snowflake as the Iceberg catalog&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; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;events &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  event_id STRING&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  event_ts TIMESTAMP_NTZ&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  customer_id STRING
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  CATALOG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;SNOWFLAKE&#39;&lt;/span&gt;
  EXTERNAL_VOLUME &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;lake_volume&#39;&lt;/span&gt;
  BASE_LOCATION &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;events&#39;&lt;/span&gt;
  ICEBERG_VERSION &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;
  ICEBERG_MERGE_ON_READ_BEHAVIOR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;AUTO&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The gotcha is scope. &lt;code&gt;ICEBERG_MERGE_ON_READ_BEHAVIOR&lt;/code&gt; only controls writes that Snowflake performs. If Spark, Flink, Trino, or another engine writes the same Iceberg table, that engine uses Iceberg table properties such as &lt;code&gt;write.delete.mode&lt;/code&gt;, &lt;code&gt;write.update.mode&lt;/code&gt;, and &lt;code&gt;write.merge.mode&lt;/code&gt;. Snowflake says it does not use those properties to choose the Snowflake write method.&lt;/p&gt;
&lt;h2 id=&quot;how-does-auto-decide-between-merge-on-read-and-copy-on-write&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-merge-read/#how-does-auto-decide-between-merge-on-read-and-copy-on-write&quot;&gt;&lt;span&gt;How does AUTO decide between merge-on-read and copy-on-write?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The new setting is really a compatibility switch disguised as a performance knob.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table case&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;AUTO behavior&lt;/th&gt;
&lt;th&gt;File type Snowflake may write&lt;/th&gt;
&lt;th&gt;Why you should care&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Snowflake-managed Iceberg v2&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Copy-on-write&lt;/td&gt;
&lt;td&gt;Rewritten data files&lt;/td&gt;
&lt;td&gt;Safest for readers that do not handle positional deletes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snowflake-managed Iceberg v3&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Merge-on-read&lt;/td&gt;
&lt;td&gt;Deletion vectors when conditions are met&lt;/td&gt;
&lt;td&gt;Better fit for frequent row-level changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Externally managed Iceberg v2&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Merge-on-read&lt;/td&gt;
&lt;td&gt;Positional delete files&lt;/td&gt;
&lt;td&gt;Snowflake follows an external-lake pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Externally managed Iceberg v3&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Merge-on-read&lt;/td&gt;
&lt;td&gt;Deletion vectors when conditions are met&lt;/td&gt;
&lt;td&gt;The cleanest path if every engine supports v3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Do not read &lt;code&gt;ENABLED&lt;/code&gt; as a promise that Snowflake will always write only delete files. Even when the setting resolves to merge-on-read, Snowflake still applies per-file heuristics. The docs say Snowflake writes a deletion vector only if fewer than approximately &lt;strong&gt;5 percent&lt;/strong&gt; of rows in a data file are deleted, and only when the file is larger than about &lt;strong&gt;1.6 MB&lt;/strong&gt;. If at least 5 percent of rows are deleted, Snowflake rewrites the file with copy-on-write.&lt;/p&gt;
&lt;p&gt;That is good engineering. A delete file for half a file is not clever. It is a future read tax with a tiny hat.&lt;/p&gt;
&lt;p&gt;The practical test is simple. If your workload deletes or updates a small share of rows across large files, merge-on-read can save write work. If your workload regularly rewrites large chunks of a partition, copy-on-write may be simpler and faster for downstream reads.&lt;/p&gt;
&lt;p&gt;You can inspect the effective parameter before 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 keyword&quot;&gt;SHOW&lt;/span&gt; PARAMETERS &lt;span class=&quot;token operator&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ICEBERG_MERGE_ON_READ_BEHAVIOR&#39;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;events&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you can reset a table override back to inherited behavior:&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; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;events
  UNSET ICEBERG_MERGE_ON_READ_BEHAVIOR&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This matters during migrations. The old boolean &lt;code&gt;ENABLE_ICEBERG_MERGE_ON_READ&lt;/code&gt; is deprecated. Snowflake says existing legacy settings are still honored when the new parameter is at &lt;code&gt;AUTO&lt;/code&gt;, but the legacy setting is ignored when the new parameter is explicitly &lt;code&gt;ENABLED&lt;/code&gt; or &lt;code&gt;DISABLED&lt;/code&gt; in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-manage#deprecated-enable-iceberg-merge-on-read&quot;&gt;new migration guidance&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 comment&quot;&gt;-- Before&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;events
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; ENABLE_ICEBERG_MERGE_ON_READ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- After&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;events
  UNSET ENABLE_ICEBERG_MERGE_ON_READ&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;events
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; ICEBERG_MERGE_ON_READ_BEHAVIOR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ENABLED&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The non-obvious migration trap is Snowflake-managed v2. Setting the legacy boolean to &lt;code&gt;TRUE&lt;/code&gt; does not force merge-on-read there when the new parameter is still &lt;code&gt;AUTO&lt;/code&gt;. To force that case, use the new parameter explicitly.&lt;/p&gt;
&lt;h2 id=&quot;where-can-this-move-your-snowflake-bill&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-merge-read/#where-can-this-move-your-snowflake-bill&quot;&gt;&lt;span&gt;Where can this move your Snowflake bill?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The parameter itself is not a new metered service. The cost shows up through the work it changes: warehouse DML, reader queries, storage optimization, and sometimes external storage requests.&lt;/p&gt;
&lt;p&gt;For Snowflake-issued DML, your warehouse still pays for the &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, or &lt;code&gt;MERGE&lt;/code&gt;. Snowflake&#39;s compute cost docs state that virtual warehouses consume credits while executing queries, loading data, and performing other DML operations in &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/cost-understanding-compute.html&quot;&gt;warehouse compute&lt;/a&gt;. Merge-on-read can reduce the amount of data rewritten during a small update, but it may add work later when readers have to merge delete files with data files.&lt;/p&gt;
&lt;p&gt;Start by measuring DML shape, not arguing about lakehouse philosophy in a meeting room.&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;
  query_type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  rows_updated&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  rows_deleted&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 keyword&quot;&gt;AS&lt;/span&gt; seconds
&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 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 operator&quot;&gt;AND&lt;/span&gt; query_type &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;UPDATE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;DELETE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;MERGE&#39;&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; query_text &lt;span class=&quot;token operator&quot;&gt;ILIKE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;%lake_db.public.events%&#39;&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 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;&lt;code&gt;QUERY_HISTORY&lt;/code&gt; keeps 365 days of query data and includes &lt;code&gt;rows_updated&lt;/code&gt; and &lt;code&gt;rows_deleted&lt;/code&gt;, according to Snowflake&#39;s &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/query_history&quot;&gt;Account Usage reference&lt;/a&gt;. Pair that with warehouse metering if you need dollar allocation, but do not pretend one query history row gives perfect per-table cost attribution in a shared warehouse.&lt;/p&gt;
&lt;p&gt;The second cost surface is compaction. Merge-on-read creates read-side debt. You pay it down by compacting files and cleaning up delete files. Snowflake&#39;s Iceberg management docs say table optimization features include data compaction, manifest compaction, and snapshot expiry. Data compaction is enabled by default for Snowflake-managed Iceberg tables, and Snowflake exposes billed compaction credits in &lt;code&gt;ICEBERG_STORAGE_OPTIMIZATION_HISTORY&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;SELECT&lt;/span&gt;
  database_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  schema_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  table_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; compaction_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;num_bytes_scanned&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; POW&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;4&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; tib_scanned&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;num_rows_written&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; rows_compacted
&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;iceberg_storage_optimization_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 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_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 punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&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; compaction_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;That view has up to &lt;strong&gt;2 hours&lt;/strong&gt; of latency and retains 365 days of history, and Snowflake says the &lt;code&gt;CREDITS_USED&lt;/code&gt; column reports credits billed for data compaction in the &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/iceberg_storage_optimization_history&quot;&gt;Iceberg storage optimization view&lt;/a&gt;. If this number rises after enabling merge-on-read, you did not get a free lunch. You moved work from the DML path into maintenance.&lt;/p&gt;
&lt;p&gt;Snowflake storage adds one more wrinkle. For Iceberg tables using Snowflake storage, Snowflake says compaction is bundled with no separate compaction charge while the table is written only by Snowflake; once an external engine performs DML or DDL through the Iceberg REST Catalog on or after May 21, 2026, compaction charges can appear in the same history view in the &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-internal-storage&quot;&gt;storage cost documentation&lt;/a&gt;. That is the kind of clause that turns a clean architecture diagram into a FinOps ticket.&lt;/p&gt;
&lt;p&gt;If external engines read Snowflake storage through Horizon Catalog, watch request counts too:&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;
  operation_type&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;count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; requests
&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;storage_request_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 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_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 keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; requests &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;Snowflake says &lt;code&gt;STORAGE_REQUEST_HISTORY&lt;/code&gt; tracks Class 1 operations such as &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;COPY&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PATCH&lt;/code&gt;, and &lt;code&gt;LIST&lt;/code&gt;, plus Class 2 operations such as &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;SELECT&lt;/code&gt;, with up to &lt;strong&gt;6 hours&lt;/strong&gt; of latency in the &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/storage_request_history&quot;&gt;storage request view&lt;/a&gt;. For Snowflake query engine access, that view is not the bill meter. For external engines, it can explain why an open table suddenly feels less open and more metered.&lt;/p&gt;
&lt;h2 id=&quot;who-should-be-allowed-to-flip-the-switch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-merge-read/#who-should-be-allowed-to-flip-the-switch&quot;&gt;&lt;span&gt;Who should be allowed to flip the switch?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Treat this like a production performance setting, not a casual table option. Snowflake&#39;s &lt;code&gt;ALTER ICEBERG TABLE&lt;/code&gt; docs say the executing role needs &lt;code&gt;OWNERSHIP&lt;/code&gt; on the Iceberg table, plus &lt;code&gt;USAGE&lt;/code&gt; on the external volume and catalog integration where applicable in the &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table&quot;&gt;access control requirements&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That should push you toward a small owner role, not a broad data engineering super-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;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; lake_db &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE iceberg_dml_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; &lt;span class=&quot;token keyword&quot;&gt;SCHEMA&lt;/span&gt; lake_db&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 keyword&quot;&gt;TO&lt;/span&gt; ROLE iceberg_dml_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;GRANT&lt;/span&gt; OWNERSHIP &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;events
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE iceberg_dml_admin
  COPY &lt;span class=&quot;token keyword&quot;&gt;CURRENT&lt;/span&gt; GRANTS&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then make the actual mode changes through reviewed migrations:&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;USE&lt;/span&gt; ROLE iceberg_dml_admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; ICEBERG &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; lake_db&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;events
  &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; ICEBERG_MERGE_ON_READ_BEHAVIOR &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;DISABLED&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The governance point is boring because it is correct: table owners can change read/write cost shape for every downstream consumer. If one team optimizes its nightly &lt;code&gt;MERGE&lt;/code&gt; and slows a dozen BI reads, you have not optimized the platform. You have moved pain to a group with worse dashboards.&lt;/p&gt;
&lt;h2 id=&quot;when-should-you-enable-merge-on-read-and-when-should-you-refuse-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-merge-read/#when-should-you-enable-merge-on-read-and-when-should-you-refuse-it&quot;&gt;&lt;span&gt;When should you enable merge-on-read, and when should you refuse it?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;AUTO&lt;/code&gt; as the default until you can name a workload that needs something else. It is conservative in exactly one place: Snowflake-managed v2. That is the place where reader compatibility is most likely to bite.&lt;/p&gt;
&lt;p&gt;Enable merge-on-read explicitly when three conditions hold:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The table sees frequent &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, or &lt;code&gt;MERGE&lt;/code&gt; operations that touch a small share of rows per data file.&lt;/li&gt;
&lt;li&gt;Your readers support the relevant Iceberg delete mechanism, positional deletes for v2 or deletion vectors for v3.&lt;/li&gt;
&lt;li&gt;You are prepared to monitor compaction through &lt;code&gt;ICEBERG_STORAGE_OPTIMIZATION_HISTORY&lt;/code&gt; for at least 30 days.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Disable it when reads dominate and latency matters more than DML speed. Also disable it when you share tables with engines that do not support Iceberg v3 deletion vectors or v2 positional delete files. Snowflake explicitly recommends &lt;code&gt;DISABLED&lt;/code&gt; for Iceberg v3 deletion vector compatibility gaps, and that advice is worth taking before your lake turns into a support matrix.&lt;/p&gt;
&lt;p&gt;For a table with heavy batch replacements, copy-on-write can be the cleaner model. If each run updates 20 percent of a partition, merge-on-read will not save you from rewriting anyway because Snowflake&#39;s heuristic flips to copy-on-write at about 5 percent of rows deleted in a file. You might still see delete files for smaller files or smaller touches, but the broad pattern is not a match.&lt;/p&gt;
&lt;p&gt;My default rollout would be boring on purpose:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Leave the account at &lt;code&gt;AUTO&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pick 3 to 5 high-DML Iceberg tables.&lt;/li&gt;
&lt;li&gt;Confirm reader compatibility by engine and version.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;ENABLED&lt;/code&gt; only at the table level.&lt;/li&gt;
&lt;li&gt;Compare 30 days of DML duration, warehouse credits, read latency, and compaction credits.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That last step is the moat. Anyone can flip a parameter. The team that wins is the one that proves where the work went.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-sensible-bet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-iceberg-merge-read/#what-is-the-sensible-bet&quot;&gt;&lt;span&gt;What is the sensible bet?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ICEBERG_MERGE_ON_READ_BEHAVIOR&lt;/code&gt; is a good Snowflake feature because it admits the lakehouse truth: open table formats do not remove trade-offs. They expose them.&lt;/p&gt;
&lt;p&gt;The right answer is not universal merge-on-read. The right answer is explicit ownership of write speed, read latency, compatibility, and compaction cost at the table boundary. Snowflake has finally given that boundary a named switch.&lt;/p&gt;
&lt;p&gt;Use it like a scalpel. Your bill will know if you use it like a broom.&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-merge-read/#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/release-notes/2026/10_20&quot;&gt;Snowflake Documentation: 10.20 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/tables-iceberg-manage&quot;&gt;Snowflake Documentation: Manage Apache Iceberg tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table-snowflake&quot;&gt;Snowflake Documentation: CREATE ICEBERG TABLE, Snowflake as the Iceberg catalog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table&quot;&gt;Snowflake Documentation: ALTER ICEBERG TABLE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/user-guide/cost-understanding-compute.html&quot;&gt;Snowflake Documentation: Understanding compute cost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/iceberg_storage_optimization_history&quot;&gt;Snowflake Documentation: ICEBERG_STORAGE_OPTIMIZATION_HISTORY view&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/storage_request_history&quot;&gt;Snowflake Documentation: STORAGE_REQUEST_HISTORY view&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: QUERY_HISTORY view&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Snowflake Adaptive Compute: the bill owner playbook</title>
    <link href="https://data-today.net/snowflake/snowflake-adaptive-compute-playbook/" />
    <updated>2026-06-08T00:00:00Z</updated>
    <id>https://data-today.net/snowflake/snowflake-adaptive-compute-playbook/</id>
    <content type="html">&lt;p&gt;Snowflake has spent years telling you the warehouse is the abstraction. Snowflake Adaptive Compute quietly says the old abstraction still leaked too much. If your team has a spreadsheet full of &lt;code&gt;MEDIUM&lt;/code&gt; versus &lt;code&gt;LARGE&lt;/code&gt;, max cluster counts, QAS settings, and angry dashboard owners, this feature is aimed directly at you.&lt;/p&gt;
&lt;p&gt;Snowflake Adaptive Compute is a new adaptive warehouse model that replaces fixed warehouse sizing with workload-aware compute. The key finding for bill owners is simple: &lt;strong&gt;you get 2 primary knobs instead of warehouse size, multi-cluster settings, Query Acceleration Service settings, and suspend policies&lt;/strong&gt;. That is a real simplification, but it is not a magic cost cutter. It moves the FinOps job from choosing node shapes to setting performance ceilings, throughput caps, and evidence-based guardrails.&lt;/p&gt;
&lt;p&gt;Snowflake lists Adaptive Compute as an open preview feature introduced in April 2026, and the docs say adaptive warehouses currently require Enterprise Edition or higher and are available only in 3 AWS regions during public preview: US West 2 (Oregon), EU West 1 (Ireland), and AP Northeast 1 (Tokyo). The official &lt;a href=&quot;https://docs.snowflake.com/en/user-guide/warehouses-adaptive&quot;&gt;Adaptive Compute documentation&lt;/a&gt; is the source of truth here, because early blog posts and preview behavior can drift.&lt;/p&gt;
&lt;h2 id=&quot;what-does-snowflake-adaptive-compute-actually-change&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-playbook/#what-does-snowflake-adaptive-compute-actually-change&quot;&gt;&lt;span&gt;What does Snowflake Adaptive Compute actually change?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Adaptive Compute changes the unit you manage. A standard Snowflake warehouse asks you to pick a size, maybe add multi-cluster scaling, choose a scaling policy, decide whether Query Acceleration Service belongs on that warehouse, and tune suspend behavior. An adaptive warehouse asks you to create a warehouse of type &lt;code&gt;ADAPTIVE&lt;/code&gt; and set 2 properties: &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 simplest valid 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 analytics_adaptive_wh&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;code&gt;MAX_QUERY_PERFORMANCE_LEVEL = XLARGE&lt;/code&gt; and &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER = 2&lt;/code&gt;. If you want to make the guardrails explicit, do it at creation time:&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 analytics_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;3&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;1800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; is the per-statement performance ceiling. It accepts 8 values: &lt;code&gt;XSMALL&lt;/code&gt;, &lt;code&gt;SMALL&lt;/code&gt;, &lt;code&gt;MEDIUM&lt;/code&gt;, &lt;code&gt;LARGE&lt;/code&gt;, &lt;code&gt;XLARGE&lt;/code&gt;, &lt;code&gt;XXLARGE&lt;/code&gt;, &lt;code&gt;XXXLARGE&lt;/code&gt;, and &lt;code&gt;X4LARGE&lt;/code&gt;. Snowflake says this value does not map to a specific underlying compute configuration. Read that twice before you put it in a chargeback deck. &lt;code&gt;XLARGE&lt;/code&gt; here is a cap on what the system may use when it has high confidence an optimization helps, not a promise that every query burns XLARGE-style resources.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt; is a non-negative integer that controls how much total query work the warehouse can run at once relative to Snowflake&#39;s internal baseline for the chosen performance level. The default is &lt;code&gt;2&lt;/code&gt;. A value of &lt;code&gt;0&lt;/code&gt; means unlimited throughput, which is the sort of setting that should require a change ticket, not a Slack shrug.&lt;/p&gt;
&lt;p&gt;Snowflake also supports the standard warehouse syntax if your IaC templates expect &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 keyword&quot;&gt;CREATE&lt;/span&gt; WAREHOUSE analytics_adaptive_wh
  &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;Here is the practical translation for an engineer who owns both latency and credits:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision you used to make&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Standard or Gen2 warehouse&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Adaptive warehouse&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Size ceiling&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;code&gt;WAREHOUSE_SIZE&lt;/code&gt;, up to &lt;code&gt;X6LARGE&lt;/code&gt; for standard warehouses&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt;, 8 levels from &lt;code&gt;XSMALL&lt;/code&gt; to &lt;code&gt;X4LARGE&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Burst control&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&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;&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt;, default &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt; for unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query Acceleration Service&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Separate feature behavior and metering&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Included in adaptive compute credits, no separate QAS credit column&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idle billing behavior&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Virtual warehouses consume credits while running, with documented minimums&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Adaptive charges begin when queries run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Main permission to change settings&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;code&gt;MODIFY&lt;/code&gt; on the warehouse&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;&lt;code&gt;MODIFY&lt;/code&gt; on the warehouse&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That table is why this is a FinOps story. Adaptive Compute removes several places where humans make bad sizing calls. It also removes several places where humans used to understand the bill through familiar warehouse-hour math.&lt;/p&gt;
&lt;h2 id=&quot;how-is-an-adaptive-warehouse-billed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-playbook/#how-is-an-adaptive-warehouse-billed&quot;&gt;&lt;span&gt;How is an adaptive warehouse billed?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Adaptive warehouses use query-based billing. Snowflake&#39;s docs say you are not charged for creating an adaptive warehouse, and charges start when the first query runs. The &lt;a href=&quot;https://www.snowflake.com/legal-files/CreditConsumptionTable.pdf&quot;&gt;Snowflake Service Consumption Table&lt;/a&gt;, effective June 4, 2026, says Adaptive Compute Services consume Platform Credits when queries run on an adaptive warehouse, with consumption scaling based on factors such as compute usage, software optimizations, and active queries.&lt;/p&gt;
&lt;p&gt;The important operational shift is this: &lt;strong&gt;there is no fixed credits-per-hour table for Adaptive Compute like the standard XS to 6XL table&lt;/strong&gt;. For standard warehouses, Snowflake publishes familiar hourly credit rates. For Adaptive Compute, the rate depends on what the query actually uses under the customer-provided settings.&lt;/p&gt;
&lt;p&gt;That makes the old mental model less useful. You can no longer say, &amp;quot;this team ran a Large for 4 hours, so we know the upper bound.&amp;quot; You need to measure the actual adaptive warehouse and per-query usage.&lt;/p&gt;
&lt;p&gt;For warehouse-level showback, keep using &lt;code&gt;SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY&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;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;ANALYTICS_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_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; &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;For adaptive per-query credit usage, the newer view is the one to watch. Snowflake&#39;s &lt;a href=&quot;https://docs.snowflake.com/en/sql-reference/account-usage/query_metering_history&quot;&gt;QUERY_METERING_HISTORY documentation&lt;/a&gt; says the view returns per-query credit usage for adaptive warehouses over the last 365 days, may lag by up to 1 hour, and can emit multiple rows for a query that spans multiple metering hours.&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;
  user_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  role_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  query_tag&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;ANALYTICS_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; &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 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 number&quot;&gt;4&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; credits_used &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;That query should be in your migration runbook before the first production conversion. If it is not, you are not testing Adaptive Compute. You are donating a workload to a preview.&lt;/p&gt;
&lt;p&gt;Snowflake&#39;s June 2, 2026 performance blog claims Adaptive Compute delivered up to 1.6x faster analytical workloads, 2.2x higher throughput for highly concurrent operational analytics, and 3.5x faster execution for DML-heavy workloads in benchmarks measured in May 2026. Treat those as vendor benchmark claims, not your committed savings plan. The chart below shows the claims you should try to reproduce on your own workload before raising throughput caps.&lt;/p&gt;
&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;https://data-today.net/posts/snowflake-adaptive-compute-playbook-fig-adaptive-performance-claims.png&quot; alt=&quot;Bar chart of Snowflake Adaptive Compute claimed benchmark gains: analytical workloads at 1.6x, highly concurrent throughput at 2.2x, and DML-heavy workloads at 3.5x.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Snowflake reports Adaptive Compute benchmark claims of up to 1.6x faster analytical workloads, 2.2x higher throughput for highly concurrent operational analytics, and 3.5x faster DML-heavy execution.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The sharp read: if your current waste comes from idle warehouses, bad suspend settings, or forgotten dev clusters, Adaptive Compute can help by changing the billing shape. If your current waste comes from expensive SQL, bad clustering, runaway BI extracts, or unlimited concurrency, Adaptive Compute can make that waste finish faster.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-convert-without-breaking-workloads&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-playbook/#how-do-you-convert-without-breaking-workloads&quot;&gt;&lt;span&gt;How do you convert without breaking workloads?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snowflake says converting to or from an adaptive warehouse is an online operation and does not interrupt running queries. 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. That overlap detail is easy to miss and painful to explain after a batch window.&lt;/p&gt;
&lt;p&gt;The conversion syntax is one line:&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 finance_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;Snowflake derives adaptive property values from the existing warehouse configuration, including warehouse size, &lt;code&gt;MAX_CLUSTER_COUNT&lt;/code&gt;, QAS scale factor, and warehouse generation. That is useful for first migration. It is not a substitute for review. After conversion, inspect the 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;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;FINANCE_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 a safer pilot, convert one warehouse that has clean query tags, stable consumers, and a known weekly pattern. A messy shared warehouse called &lt;code&gt;REPORTING_WH&lt;/code&gt; used by 19 tools is a lousy first candidate. If you need a refresher on the old sizing model you are leaving behind, our &lt;a href=&quot;https://data-today.net/snowflake/snowflake-gen2-warehouses/&quot;&gt;Snowflake Gen2 warehouse guide&lt;/a&gt; covers the fixed-size trade-offs Adaptive Compute is trying to retire.&lt;/p&gt;
&lt;p&gt;You can tune the adaptive properties after conversion:&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 finance_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;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 pilot goes badly, 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 finance_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;Do not bulk convert until you have 2 weeks of before and after evidence. Snowflake provides &lt;code&gt;SYSTEM$BULK_UPDATE_WH&lt;/code&gt;, including a dry-run mode, but the existence of a bulk function is not an argument for using it on Monday morning.&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; SYSTEM$BULK_UPDATE_WH&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;WAREHOUSE_TYPE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&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;span class=&quot;token string&quot;&gt;&#39;{&quot;WAREHOUSE_TYPE&quot;: &quot;STANDARD&quot;}&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;DRY_RUN&#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;When the dry run matches exactly what you expect, and only then, use &lt;code&gt;ACTIVE&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;SELECT&lt;/span&gt; SYSTEM$BULK_UPDATE_WH&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;WAREHOUSE_TYPE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&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;span class=&quot;token string&quot;&gt;&#39;{&quot;WAREHOUSE_TYPE&quot;: &quot;STANDARD&quot;}&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;ACTIVE&#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;Preview limits matter. During public preview, Snowflake says you cannot convert to or from &lt;code&gt;X5LARGE&lt;/code&gt; or &lt;code&gt;X6LARGE&lt;/code&gt; warehouses, and you cannot convert to or from Snowpark-optimized or interactive warehouses. If you run high-memory Snowpark jobs, do not force them through Adaptive Compute just because the word adaptive sounds modern.&lt;/p&gt;
&lt;h2 id=&quot;what-should-you-monitor-after-the-switch&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-playbook/#what-should-you-monitor-after-the-switch&quot;&gt;&lt;span&gt;What should you monitor after the switch?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start with queuing. &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt; is an admission-control lever, so &lt;code&gt;WAREHOUSE_LOAD_HISTORY&lt;/code&gt; should be in the first dashboard. If queued overload time rises after migration, you probably set the multiplier too low for the workload&#39;s peak shape.&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 punctuation&quot;&gt;,&lt;/span&gt;
  avg_queued_provisioning
&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;ANALYTICS_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;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;Then compare latency and queuing by query tag. This is where teams with sloppy tagging pay the tax. If your dbt jobs, BI dashboards, notebooks, and ad hoc admin queries all share a blank &lt;code&gt;QUERY_TAG&lt;/code&gt;, Adaptive Compute will not fix your accountability problem.&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_tag&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 operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; avg_elapsed_seconds&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 operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; avg_queue_seconds
&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;ANALYTICS_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; &lt;span class=&quot;token number&quot;&gt;1&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; avg_queue_seconds &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;Use the adaptive-specific metering view for credits, and use query history for behavior. The combination tells you whether a setting change bought throughput, masked bad SQL, or simply moved spend around.&lt;/p&gt;
&lt;p&gt;One more governance point: separate the people who can use the warehouse from the people who can widen the blast radius. Snowflake&#39;s &lt;a href=&quot;https://docs.snowflake.com/sql-reference/sql/alter-warehouse&quot;&gt;ALTER WAREHOUSE access-control docs&lt;/a&gt; list &lt;code&gt;MODIFY&lt;/code&gt;, &lt;code&gt;MONITOR&lt;/code&gt;, &lt;code&gt;OPERATE&lt;/code&gt;, and &lt;code&gt;USAGE&lt;/code&gt; as warehouse privileges, and the global &lt;code&gt;MANAGE WAREHOUSES&lt;/code&gt; privilege is equivalent to &lt;code&gt;MODIFY&lt;/code&gt;, &lt;code&gt;MONITOR&lt;/code&gt;, and &lt;code&gt;OPERATE&lt;/code&gt; across all warehouses.&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 punctuation&quot;&gt;,&lt;/span&gt; MONITOR
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; WAREHOUSE analytics_adaptive_wh
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE analytics_engineer&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 analytics_adaptive_wh
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE finops_platform_owner&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 analytics_adaptive_wh
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; ROLE platform_operations&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;QUERY_THROUGHPUT_MULTIPLIER = 0&lt;/code&gt; means unlimited throughput. You do not want every dashboard owner to discover that setting during quarter close.&lt;/p&gt;
&lt;h2 id=&quot;when-is-adaptive-compute-the-wrong-choice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://data-today.net/snowflake/snowflake-adaptive-compute-playbook/#when-is-adaptive-compute-the-wrong-choice&quot;&gt;&lt;span&gt;When is Adaptive Compute the wrong choice?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Adaptive Compute is the wrong first move when you need strict predictability more than managed optimization. If a finance reporting workload runs the same 120 queries every morning with stable concurrency and a well-tuned Gen2 warehouse, Adaptive Compute may add a layer of opacity without enough benefit. The docs explicitly say standard Gen2 warehouses remain the better fit when you need direct control over warehouse size and scaling policy.&lt;/p&gt;
&lt;p&gt;It is also the wrong fit for workloads Snowflake calls out elsewhere: primarily HTAP workloads may belong on standard Gen2, very low-latency dashboards and data-backed applications may belong on interactive warehouses, and high-memory Snowpark or machine-learning jobs may belong on Snowpark-optimized warehouses.&lt;/p&gt;
&lt;p&gt;The best candidates have variance. Think mixed BI and ETL, ad hoc analytics, data loading pipelines with changing parallelism, and teams that keep overprovisioning because the worst 15 minutes of the day dominate the warehouse setting. If you are already running 12 warehouses mostly to preserve chargeback names and avoid stepping on each other&#39;s concurrency, adaptive warehouses let you keep those logical names while routing work into an account-dedicated adaptive pool.&lt;/p&gt;
&lt;p&gt;Here is the decision rule: &lt;strong&gt;migrate where human sizing decisions are the bottleneck, not where deterministic control is the product requirement&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-would-i-do-before-trusting-it-with-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-playbook/#what-would-i-do-before-trusting-it-with-production-spend&quot;&gt;&lt;span&gt;What would I do before trusting it with production spend?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run a controlled pilot with a budget, a rollback, and a scoreboard. Pick 1 warehouse, 3 success metrics, and 14 days. The metrics should include credits from &lt;code&gt;WAREHOUSE_METERING_HISTORY&lt;/code&gt;, top query costs from &lt;code&gt;QUERY_METERING_HISTORY&lt;/code&gt;, and queue behavior from &lt;code&gt;WAREHOUSE_LOAD_HISTORY&lt;/code&gt;. If you cannot name the success metric before the migration, the migration is theater.&lt;/p&gt;
&lt;p&gt;A practical pilot sequence looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Capture 14 days of baseline credits, p95 elapsed time, and queued overload time for the standard or Gen2 warehouse.&lt;/li&gt;
&lt;li&gt;Convert with &lt;code&gt;ALTER WAREHOUSE ... SET WAREHOUSE_TYPE = &#39;ADAPTIVE&#39;&lt;/code&gt; during a low-risk window.&lt;/li&gt;
&lt;li&gt;Keep the default &lt;code&gt;XLARGE&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt; for the first 48 hours unless a resource monitor fires.&lt;/li&gt;
&lt;li&gt;Lower &lt;code&gt;MAX_QUERY_PERFORMANCE_LEVEL&lt;/code&gt; if a few queries dominate spend without business value.&lt;/li&gt;
&lt;li&gt;Raise &lt;code&gt;QUERY_THROUGHPUT_MULTIPLIER&lt;/code&gt; only if queueing hurts a named workload.&lt;/li&gt;
&lt;li&gt;Roll back if credits rise and the latency gain is not worth it to the business owner.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Adaptive Compute is Snowflake admitting that warehouse tuning became a product surface area of its own. Good. Most data teams have better things to do than debate &lt;code&gt;MEDIUM&lt;/code&gt; versus &lt;code&gt;LARGE&lt;/code&gt; for the fifth time this quarter. But the bill does not disappear. It just becomes more query-shaped.&lt;/p&gt;
&lt;p&gt;The teams that win with Adaptive Compute will not be the teams that turn every knob to maximum. They will be the teams that treat the 2 knobs like production APIs: versioned, monitored, reviewed, and boring on purpose.&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-playbook/#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/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/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;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://www.snowflake.com/legal-files/CreditConsumptionTable.pdf&quot;&gt;Snowflake Legal: Snowflake Service Consumption Table&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <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>