Explanation
Why the waste happens and who it affects.
Every refresh finds the changed data, copies it across regions and bills the target account for both the data transfer and the replication compute, while the secondary databases add a second full copy of storage. Snowflake states that the monthly bill depends on how much table data changes and how often secondaries are refreshed.
Waste appears when groups are scoped more broadly than the recovery or data-sharing need: every database in an account added to one failover group, staging, scratch or high-churn ETL databases replicated alongside the few that actually need DR, or a REPLICATION_SCHEDULE of a few minutes applied to data whose recovery point objective is hours or a day. Groups set up for a migration, a proof of concept or a consumer that has since moved on also keep refreshing, because nothing stops a schedule until someone suspends or drops the secondary group.
Billing model
The pricing dimensions that drive this cost.
Replication charges are billed on the target account, the one that holds the secondary group being refreshed.
- Replication data transfer
- Cross-region or cross-cloud transfer of the initial copy and every subsequent refresh, at rates that depend on the source account's region and cloud
- Replication compute
- Snowflake-provided compute for finding metadata and data deltas and copying them, shown with service type REPLICATION in usage views
- Optimized refresh
- For eligible failover groups, billed at 5 credits per TB replicated plus 0.2 credits per 10,000 changed objects beyond 25 million per month, instead of compute time
- Secondary storage
- Standard storage for the secondary databases in the target account, plus any background maintenance for materialized views and search optimization there
How to detect
5 checks to find it in your estate.
- In each target account, query SNOWFLAKE.ACCOUNT_USAGE.REPLICATION_GROUP_USAGE_HISTORY (hourly CREDITS_USED and BYTES_TRANSFERRED per secondary group, 365 days) to rank groups by replication cost
- Use DATABASE_REPLICATION_USAGE_HISTORY to see which individual databases account for most of the transferred bytes and credits
- Run SHOW REPLICATION GROUPS and SHOW FAILOVER GROUPS and review replication_schedule, object_types and secondary_state; flag schedules measured in minutes on groups whose recovery point objective is much longer
- List the databases in each group with SHOW DATABASES IN REPLICATION GROUP (or FAILOVER GROUP) and flag scratch, staging, sandbox and intermediate ETL databases that have no DR or cross-region consumer
- Check QUERY_HISTORY or ACCESS_HISTORY in the target account for reads of replicated databases that exist for data sharing or reporting rather than failover, and flag secondaries that nobody queries
How to fix
5 ways to remove the waste.
- Narrow each group to the databases and object types that actually need a secondary copy, using ALTER REPLICATION GROUP ... REMOVE <db> FROM ALLOWED_DATABASES; a database removed from the primary group is dropped in linked target accounts at the next refresh unless the secondary group is dropped first, which leaves standalone read-write copies
- Move databases with different recovery needs into separate groups so critical data can keep a short schedule while the rest refreshes hourly or daily
- Lengthen REPLICATION_SCHEDULE (an interval in minutes, up to 11,520, or a CRON expression) to match the recovery point objective, so fewer refreshes run and each one's delta-detection compute is spread over more changes
- Suspend scheduled refreshes on secondary groups that are temporarily not needed with ALTER REPLICATION GROUP ... SUSPEND, and drop secondary groups and databases that no longer serve a purpose; Snowflake notes that ceasing refresh operations stops replication costs
- Reduce churn in replicated databases where possible, for example by keeping transient staging tables and frequently rebuilt intermediate tables in a database outside the replication group
Documentation
Vendor references for pricing and configuration.