{"id":104827,"date":"2024-11-25T22:10:36","date_gmt":"2024-11-25T22:10:36","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=104827"},"modified":"2024-12-11T03:12:54","modified_gmt":"2024-12-11T03:12:54","slug":"essential-strategies-for-optimizing-snowflake-performance-and-reducing-costs","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/snowflake\/essential-strategies-for-optimizing-snowflake-performance-and-reducing-costs\/","title":{"rendered":"Essential Strategies for Optimizing Snowflake Performance and Reducing Costs"},"content":{"rendered":"\n<p>In today\u2019s data-driven enterprise environment, businesses increasingly rely on Snowflake\u2019s cloud data warehouse for handling large-scale data analytics and storage needs. However, optimizing Snowflake performance is crucial to manage growing data warehouse costs and maintain efficiency. This guide shares actionable strategies for reducing Snowflake expenses while boosting query performance and scalability. Snowflake offers many benefits, but it could also be more expensive if you don\u2019t apply optimizations, and I learned it when my organization&#8217;s snowflake bill increased exponentially as the usage increased.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-understanding-snowflake-s-cost-structure\"><a id=\"post-104827-_heading=h.1fob9te\"><\/a>Understanding Snowflake&#8217;s Cost Structure<\/h2>\n\n\n\n<p>Before diving into optimization strategies, it&#8217;s crucial to understand how Snowflake&#8217;s pricing model works. Unlike traditional data warehouses, Snowflake&#8217;s consumption-based pricing model means you pay for what you use, but this also presents unique opportunities for optimization.<\/p>\n\n\n\n<p><strong><em>Note: all prices are subject to change and should be used for relative magnitude only. Costs are very subject to change, so be sure to check out <\/em><\/strong><a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/cost-understanding-compute\"><strong><em>Snowflake\u2019s documentation<\/em><\/strong><\/a><strong><em>. For current up to date cost structures before committing to a new contract\/subscription. <\/em><\/strong><\/p>\n\n\n\n<p><a id=\"post-104827-_heading=h.3znysh7\"><\/a> There are three core cost components in Snowflake\u2019s cost structure. Compute, Storage, and Data Transfer.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-compute-costs\">Compute Costs <\/h3>\n\n\n\n<p>Compute costs are billed in <strong>credits<\/strong>. Credits are Snowflake&#8217;s primary billing unit for compute resources. Every time you run a virtual warehouse, you consume credits based on the warehouse size and runtime. Let me walk through a couple of scenarios in configuring a <a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/warehouses\">Virtual Warehouse<\/a>.<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><strong>Credits\/hour<\/strong> are based on warehouse size:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>X-Small (XS): 1<\/li>\n\n\n\n<li>Small (S): 2<\/li>\n\n\n\n<li>Medium (M): 4<\/li>\n\n\n\n<li>Large (L): 8<\/li>\n\n\n\n<li>X-Large (XL): 16<\/li>\n\n\n\n<li>2X-Large (2XL): 32<br><\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Examples:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Scenario 1: Daily ETL Workload &#8211;\u00a0A <strong>Large warehouse<\/strong> running for 4 hours\/day over 30 days costs <strong>704 credits\/month<\/strong> at $2\/credit = <strong>$1,408<\/strong>.<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Calculation:<br>Daily Credits: 8 credits\/hour \u00d7 4 hours = 32 credits<br>Monthly Credits: 32 credits \u00d7 30 business days = 906 credits<br>Monthly Cost: 906 credits \u00d7 $2\/credit = $1,812<br><\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li>Scenario 2: BI Query Workload &#8211; A <strong>Medium warehouse<\/strong> running for 8 hours\/day over 30 days costs <strong>960 credits\/month<\/strong> at $3\/credit = <strong>$2,880<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Calculation:<br>Daily Credits: 4 credits\/hour \u00d7 8 hours = 32 credits<br>Monthly Credits: 32 credits \u00d7 30 days = 960 credits<br>Monthly Cost: 960 credits \u00d7 $3\/credit = $2,880<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-storage-costs\">Storage Costs<\/h3>\n\n\n\n<p>Storage costs represent data that is being persisted. For example for Active storage, staging, used for <a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/data-failsafe\">fail safe<\/a>, <a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/data-time-travel\">time travel<\/a>, platform costs (Cloud platform (AWS, Azure, GCP)). etc..<\/p>\n\n\n\n<p><strong>Types of storage affect your bill:<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><strong>Active Storage<\/strong>: Currently used data<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Compressed and optimized automatically.<\/li>\n\n\n\n<li>Rates typically range from $23 to $40 per TB per month.<\/li>\n\n\n\n<li>Varies by region and cloud provider.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Time Travel Storage<\/strong>: Historical data versions<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Cost varies based on retention period.<\/li>\n\n\n\n<li>Standard Edition: 1 day included.<\/li>\n\n\n\n<li>Enterprise Edition: Up to 90 days<\/li>\n\n\n\n<li>Additional storage needs can significantly impact costs.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Fail-safe Storage<\/strong>: 7-day disaster recovery backup<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>No direct charge in most editions<\/li>\n\n\n\n<li>Included in overall storage calculations.<\/li>\n\n\n\n<li>Critical for compliance and recovery<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div>\n\n\n<p><strong>Real-World Storage Example:<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul id=\"block-de7a9188-ba56-412a-83a5-79f45cf5968a\" class=\"wp-block-list\">\n<li><strong>Items stored:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Average Data Storage: 5 TB<\/li>\n\n\n\n<li>Time Travel Storage: 1 TB<\/li>\n\n\n\n<li>Fail-safe Storage: 2 TB<\/li>\n\n\n\n<li>Storage Rate: $40\/TB\/month<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Calculation:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Total Storage: 8 TB<\/li>\n\n\n\n<li>Monthly Storage Cost: 8 TB \u00d7 $40\/TB = $320<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-data-transfer-costs\"><strong>Data Transfer Costs<\/strong><\/h3>\n\n\n\n<p>Snowflake charges for data transfer based on different scenarios and directions of data movement. Let&#8217;s break down each type with explanations and an example.<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><strong>Cross-region data movement<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Costs range from $20 to $200 per TB.<\/li>\n\n\n\n<li>Varies by cloud provider and regions involved.<\/li>\n\n\n\n<li>Some regions have higher costs due to infrastructure.<\/li>\n\n\n\n<li>Example: Moving 1TB of data between AWS regions could cost $100-200<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Moving 1TB of data between AWS regions:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>US East to US West: ~$20\/TB<\/li>\n\n\n\n<li>US to Europe: ~$100\/TB<\/li>\n\n\n\n<li>US to Asia: ~$200\/TB<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>External table access<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Costs depend on source location.<\/li>\n\n\n\n<li>Frequency of access impacts total cost<\/li>\n\n\n\n<li>Caching can help reduce repeated transfer costs.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Data sharing between accounts<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Provider account bears compute costs<\/li>\n\n\n\n<li>No transfer costs for same region sharing<\/li>\n\n\n\n<li>Cross-region sharing incurs additional fees.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong><a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/data-load-snowpipe-intro\">Snowpipe<\/a> ingestion<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Additional charges apply for auto-ingestion infrastructure.<\/li>\n\n\n\n<li>Per-file ingestion fees may apply<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-dig-deeper-into-these-components\">Dig deeper into these components<\/h3>\n\n\n\n<p>Understanding these cost components and their variations is crucial for:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Budget planning<\/li>\n\n\n\n<li>Resource allocation<\/li>\n\n\n\n<li>Optimization strategies<\/li>\n\n\n\n<li>Cost forecasting<\/li>\n\n\n\n<li>Capacity planning<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Each component can be optimized independently, but they often interact with each other. For example, better compute optimization might require more storage for materialized views, or reduced storage costs might lead to increased compute costs for real-time processing.<\/p>\n\n\n\n<p>If you want to know more, you can check out the Snowflake Documentation on costs <a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/cost-understanding-overall\">here<\/a>.<\/p>\n\n\n\n<p><a id=\"post-104827-_heading=h.2et92p0\"><\/a><a id=\"post-104827-_heading=h.tyjcwt\"><\/a> Now that you have a fair idea of how cost is calculated in Snowflake, let\u2019s dive into optimizations by starting with the warehouse optimization which is the highest cost contributor.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-immediate-cost-optimization-strategies\"><a id=\"post-104827-_heading=h.3dy6vkm\"><\/a>Immediate Cost Optimization Strategies<\/h2>\n\n\n\n<p>In this section, I will cover some of the more immediate cost optimizations you can use to save money pretty quickly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-auto-suspension-configuration-in-snowflake\"><a id=\"post-104827-_heading=h.1t3h5sf\"><\/a>Auto-Suspension Configuration in Snowflake<\/h3>\n\n\n\n<p>The auto-suspension feature is crucial for controlling costs, especially for workloads with intermittent activity. Warehouses take about 1-2 seconds to resume, so the impact on query performance is minimal for most use cases.<\/p>\n\n\n\n<p>Minimize idle costs using the following SQL:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ALTER WAREHOUSE COMPUTE_WH  \n  SET AUTO_SUSPEND = 300, \n  AUTO_RESUME = TRUE;  <\/pre>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><strong>What this does:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Sets the warehouse to automatically suspend after 5 minutes of inactivity.<\/li>\n\n\n\n<li>Enables automatic resume when new queries arrive.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Cost Impact:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>If your warehouse runs 24\/7 without auto-suspension, you&#8217;re paying for idle time.<\/li>\n\n\n\n<li>For a Medium warehouse (4 credits\/hour):<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Without Auto-suspend: 24 hours \u00d7 4 credits = 96 credits\/day (<strong>$192\/day<\/strong> at $2\/credit)<\/li>\n\n\n\n<li>With Auto-suspend (8 active hours): 8 hours \u00d7 4 credits = 32 credits\/day (<strong>$64\/day<\/strong>)<\/li>\n\n\n\n<li>Daily Savings: $128 or <strong>67% saving.<\/strong><\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-multi-cluster-configuration-for-scalability\"><a id=\"post-104827-_heading=h.4d34og8\"><\/a>Multi-Cluster Configuration for Scalability<\/h3>\n\n\n\n<p>Enable auto-scaling for dynamic workloads to adjust clusters to match workload demands. This is particularly useful for scenarios with variable query loads, such as:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Morning report generation peaks<\/li>\n\n\n\n<li>End-of-month financial processing.<\/li>\n\n\n\n<li>Concurrent user query spikes during business hours<\/li>\n<\/ul>\n<\/div>\n\n\n<pre class=\"wp-block-preformatted\">ALTER WAREHOUSE COMPUTE_WH  \n  SET MIN_CLUSTER_COUNT = 1, \n  MAX_CLUSTER_COUNT = 3, \n  SCALING_POLICY = 'STANDARD';  <\/pre>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><strong>What this does:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Sets minimum cluster count to 1 (baseline capacity)<\/li>\n\n\n\n<li>Allows automatic scaling up to 3 clusters based on workload.<\/li>\n\n\n\n<li>Uses standard scaling policy for balanced scaling decisions.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Cost Impact: <\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>While multiple clusters increase concurrent processing capability, they multiply credit consumption:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Single Cluster (Medium): 4 credits\/hour<\/li>\n\n\n\n<li>Three Clusters: 12 credits\/hour<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li>Peak Hour Cost Comparison (Enterprise Edition at $3\/credit):<\/li>\n\n\n\n<li>Single Cluster: 4 credits \u00d7 $3 = $12\/hour<\/li>\n\n\n\n<li>Three Clusters: 12 credits \u00d7 $3 = $36\/hour<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div>\n\n\n<p>Note: These costs are in addition to the standard warehouse size pricing discussed earlier. Multi-clustering is particularly cost-effective when query queuing would otherwise impact business operations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-specialized-warehouse-creation-for-workload-segmentation\"><a id=\"post-104827-_heading=h.2s8eyo1\"><\/a>Specialized Warehouse Creation for Workload Segmentation<\/h3>\n\n\n\n<p>Separate ETL and BI workloads. Different workload types have distinct resource needs and timing patterns. For example:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>ETL processes often need more compute power but run in shorter bursts.<\/li>\n\n\n\n<li>BI queries typically require less power but run throughout the day.<\/li>\n\n\n\n<li>Data science workloads might need large warehouses for specific operations.<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Here&#8217;s how to configure warehouses for these different needs:<\/p>\n\n\n\n<p>ETL:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- ETL Warehouse\nCREATE WAREHOUSE ETL_WH \nWITH WAREHOUSE_SIZE = 'LARGE'\n     AUTO_SUSPEND = 600\n     AUTO_RESUME = TRUE\n     INITIALLY_SUSPENDED = TRUE; <\/pre>\n\n\n\n<p>BI:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- BI Warehouse\nCREATE WAREHOUSE BI_WH\nWITH WAREHOUSE_SIZE = 'MEDIUM'\n     AUTO_SUSPEND = 300\n     AUTO_RESUME = TRUE\n     INITIALLY_SUSPENDED = TRUE;<\/pre>\n\n\n\n<p><strong>What this does:<\/strong><\/p>\n\n\n\n<p>Creates separate warehouses for ETL and BI workloads.<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><strong>ETL warehouse:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>LARGE size for processing power (8 credits\/hour)<\/li>\n\n\n\n<li>10-minute auto-suspend for batch jobs<\/li>\n\n\n\n<li>Starts suspended to prevent unnecessary credits.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>BI warehouse<\/strong>:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>MEDIUM size for interactive queries (4 credits\/hour)<\/li>\n\n\n\n<li>5-minute auto-suspend for interactive usage<\/li>\n\n\n\n<li>Starts suspended to prevent unnecessary credits.<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div>\n\n\n<p><strong>Cost Impact Example:<br><\/strong> <br><em>ETL Warehouse (4 hours\/day):<\/em><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>8 credits\/hour \u00d7 4 hours = 32 credits\/day<\/li>\n<\/ul>\n<\/div>\n\n\n<p><em>BI Warehouse (8 hours\/day):<\/em><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>4 credits\/hour \u00d7 8 hours = 32 credits\/day<\/li>\n\n\n\n<li>Total Daily Credits: 64 credits<\/li>\n\n\n\n<li>Daily Cost (Standard Edition): 64 credits \u00d7 $2 = $128<\/li>\n<\/ul>\n<\/div>\n\n\n<p><em>Compared to single LARGE warehouse running 12 hours:<\/em><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>8 credits\/hour \u00d7 12 hours = 96 credits<\/li>\n\n\n\n<li>Daily Cost: 96 credits \u00d7 $2 = $192<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Daily Savings: $64<\/p>\n\n\n\n<p>The separation of workloads often leads to better overall performance despite using smaller warehouses for some tasks. ETL jobs can run faster on a dedicated large warehouse, while BI queries benefit from consistent, right-sized resources. This approach can actually reduce total processing time and thus credit consumption.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-best-practices-for-cost-efficient-warehouse-management\"><a id=\"post-104827-_heading=h.17dp8vu\"><\/a>Best Practices for Cost-Efficient Warehouse Management<\/h3>\n\n\n\n<p>Understanding how to effectively manage warehouse resources is crucial for both cost control and performance optimization. Here are key strategies based on real-world implementations:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><strong>Size Planning:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Start with smaller warehouses and scale up based on performance metrics.<\/li>\n\n\n\n<li>Monitor query execution times and credit consumption.<\/li>\n\n\n\n<li>Use query history to identify optimal warehouse sizes.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Workload Segregation:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Separate ETL and BI workloads to different warehouses<\/li>\n\n\n\n<li>Match warehouse size to workload characteristics.<\/li>\n\n\n\n<li>Consider time zones for global operations.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Auto-scaling Strategy:<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Set appropriate <code>MIN_CLUSTER_COUNT<\/code> based on minimum concurrent users.<\/li>\n\n\n\n<li>Adjust <code>MAX_CLUSTER_COUNT<\/code> based on peak load requirements.<\/li>\n\n\n\n<li>Monitor scaling patterns to optimize settings.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Monitoring Query Performance:<\/strong><\/li>\n<\/ul>\n<\/div>\n\n\n<pre class=\"wp-block-preformatted\">SELECT warehouse_name,\n       COUNT(*) as query_count,\n       AVG(execution_time) as avg_execution_time,\n       SUM(credits_used) as total_credits,\n       SUM(credits_used)\/COUNT(*) as credits_per_query\nFROM snowflake.account_usage.query_history\nWHERE start_time &gt;= dateadd('day', -7, current_timestamp())\nGROUP BY 1\nORDER BY 3 DESC;<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-query-optimization-techniques-in-snowflake\"><a id=\"post-104827-_heading=h.3rdcrjn\"><\/a>Query Optimization Techniques in Snowflake<\/h2>\n\n\n\n<p>Based on experience optimizing enterprise-scale data platforms, here are key query optimization strategies that have proven effective in real-world scenarios:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-leverage-clustering-for-better-query-performance\"><a id=\"post-104827-_heading=h.26in1rg\"><\/a>Leverage Clustering for Better Query Performance<\/h3>\n\n\n\n<p>Clustering in Snowflake refers to the physical organization of table data based on one or more columns. Think of it as similar to traditional database indexing, but with some key differences. Here&#8217;s how to implement it:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE OR REPLACE TABLE sales_data (\n    transaction_date DATE,\n    store_id VARCHAR,\n    product_id VARCHAR,\n    sale_amount NUMBER(38,2)\n) CLUSTER BY (transaction_date, store_id);<\/pre>\n\n\n\n<p><strong>Explanation:<\/strong><\/p>\n\n\n\n<p>Clustering helps physically organize data to improve query performance. While clustering generally helps queries that filter on clustered columns, it may not benefit for:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Queries that scan all data (full table scans)<\/li>\n\n\n\n<li>Queries that don&#8217;t filter on clustered columns.<\/li>\n\n\n\n<li>Tables with frequent updates to clustered columns<\/li>\n<\/ul>\n<\/div>\n\n\n<p>In this example, we cluster by transaction_date and store_id. When queries filter on these columns, Snowflake can skip scanning irrelevant data micro-partitions.<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Reduces I\/O and improves query execution time<\/li>\n\n\n\n<li>Particularly effective for frequently queried columns<\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-use-materialized-views-for-frequent-queries\"><a id=\"post-104827-_heading=h.lnxbz9\"><\/a>Use Materialized Views for Frequent Queries<\/h3>\n\n\n\n<p>Materialized views can significantly improve performance for frequently run complex queries, but they come with maintenance overhead:<\/p>\n\n\n\n<p>Pre-compute results to optimize query execution:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- Create a materialized view for aggregated daily sales\nCREATE OR REPLACE MATERIALIZED VIEW daily_sales_summary AS\nSELECT \n    DATE_TRUNC('day', transaction_date) as sale_date,\n    store_id,\n    product_category,\n    SUM(sale_amount) as total_sales,\n    COUNT(*) as transaction_count,\n    AVG(sale_amount) as average_transaction_value\nFROM sales_data\nGROUP BY 1, 2, 3;<\/pre>\n\n\n\n<p><strong>Explanation:<\/strong><\/p>\n\n\n\n<p>Materialized views pre-compute and store query results<\/p>\n\n\n\n<p>Pros:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Reduces computational overhead for repetitive queries.<\/li>\n\n\n\n<li>Automatically maintained by Snowflake.<\/li>\n\n\n\n<li>Can dramatically improve query performance.<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Cons:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Consumes additional storage.<\/li>\n\n\n\n<li>Updates consume credits.<\/li>\n\n\n\n<li>May not be cost-effective for infrequently accessed data.<\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-predicate-pushdown-optimization\"><a id=\"post-104827-_heading=h.35nkun2\"><\/a>Predicate Pushdown Optimization<\/h3>\n\n\n\n<p>Understanding predicate pushdown helps write more efficient queries:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- Inefficient Query\nSELECT * FROM large_table\nWHERE complex_transformation(column) = 'value';\n-- Optimized Query\nSELECT * FROM large_table\nWHERE column IN (\n    SELECT column \n    FROM lookup_table \n    WHERE complex_condition\n);<\/pre>\n\n\n\n<p><strong>Explanation:<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Predicate pushdown moves filtering conditions closer to data source.<\/li>\n\n\n\n<li>Reduces amount of data processed and transferred.<\/li>\n\n\n\n<li>Allows Snowflake to leverage clustering and micro-partition pruning.<\/li>\n\n\n\n<li>Minimizes unnecessary data scanning and movement.<\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-window-function-optimization\"><a id=\"post-104827-_heading=h.1ksv4uv\"><\/a>Window Function Optimization<\/h3>\n\n\n\n<p>Window functions are powerful SQL features that perform calculations across a set of rows related to the current row. While extremely useful, they can impact performance if not optimized properly. Snowflake provides specific optimizations and features to make window functions more efficient.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-understanding-qualify-clause\"><a id=\"post-104827-_heading=h.48ueiwmbaojl\"><\/a>Understanding QUALIFY Clause<\/h4>\n\n\n\n<p>Snowflake introduces the <code>QUALIFY<\/code> clause as a unique optimization feature that isn&#8217;t available in standard SQL. This clause allows filtering on window functions without using subqueries or CTEs (Common Table Expressions), resulting in more efficient execution and cleaner code.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-common-window-function-scenarios-and-optimizations\">Common Window Function Scenarios and Optimizations:<\/h4>\n\n\n\n<p>In this section I will show a few examples of using window functions:<\/p>\n\n\n\n<p><strong>Top N Records Per Group<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- Less Efficient Approach (Using CTE)\nWITH ranked_sales AS (\n    SELECT \n        store_id, \n        sale_amount,\n        ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY sale_amount DESC) as rank\n    FROM sales_data\n)\nSELECT * FROM ranked_sales WHERE rank &lt;= 10;\n-- Optimized Approach (Using QUALIFY)\nSELECT \n    store_id, \n    sale_amount,\n    ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY sale_amount DESC) as rank\nFROM sales_data\nQUALIFY rank &lt;= 10;<\/pre>\n\n\n\n<p><strong>Performance Impact:<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Eliminates the need for temporary result storage.<\/li>\n\n\n\n<li>Reduces memory usage.<\/li>\n\n\n\n<li>Allows Snowflake to optimize the entire operation as a single unit.<\/li>\n\n\n\n<li>Typically, 20-30% faster for large datasets<\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-join-optimization-techniques\"><a id=\"post-104827-_heading=h.44sinio\"><\/a>Join Optimization Techniques<\/h3>\n\n\n\n<p>Understanding join behavior and optimization is crucial for query performance:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-- Inefficient Join<br>SELECT <br>    s.store_name, <br>    t.transaction_amount<br>FROM stores s<br>LEFT JOIN transactions t ON s.store_id = t.store_id;<br><br>-- Optimized Join with Join Filtering<br>SELECT <br>    s.store_name, <br>    t.transaction_amount<br>FROM stores s<br>LEFT JOIN transactions t <br>    ON s.store_id = t.store_id<br>    AND t.transaction_date >= '2023-01-01'<br>    AND t.transaction_amount > 100;<\/pre>\n\n\n\n<p><strong>Explanation:<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Join filters in the ON clause can improve performance by:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Reducing the amount of data before the join<\/li>\n\n\n\n<li>Allowing better use of clustering and partition pruning<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li>For <code>LEFT JOIN<\/code>s, conditions in the ON clause vs <code>WHERE<\/code> clause behave differently:<\/li>\n\n\n\n<li><code>ON<\/code> clause: Filters only the right table<\/li>\n\n\n\n<li><code>WHERE<\/code> clause: Filters after the join<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Choose based on your specific needs and data relationships.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-best-practices-for-query-optimization\"><a id=\"post-104827-_heading=h.2jxsxqh\"><\/a>Best Practices for Query Optimization<\/h2>\n\n\n<div class=\"block-core-list\">\n<ol class=\"wp-block-list\">\n<li><strong>Use Appropriate Data Types<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Choose the smallest possible numeric precision.<\/li>\n\n\n\n<li><code>VARCHAR<\/code> in Snowflake automatically optimizes storage<\/li>\n\n\n\n<li>Use <code>VARCHAR<\/code> with appropriate length<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Leverage Query Result Caching<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Results are cached for 24 hours.<\/li>\n\n\n\n<li>Caching works for identical queries including:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Same text (including spaces and comments)<\/li>\n\n\n\n<li>Same parameter values<\/li>\n\n\n\n<li>Same session settings<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Minimize Data Movement<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Use local joins when possible.<\/li>\n\n\n\n<li>Avoid unnecessary data transformations.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li><strong>Monitor and Analyze Query Performance<\/strong><div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Use <code>EXPLAIN<\/code> command to understand query execution plan.<\/li>\n\n\n\n<li>Review <code>QUERY_HISTORY<\/code> for performance insights.<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ol>\n<\/div>\n\n\n<pre class=\"wp-block-preformatted\">-- Query Performance Analysis\nSELECT \n    query_text,\n    total_elapsed_time,\n    bytes_scanned,\n    bytes_spilled_to_local_storage,\n    bytes_spilled_to_remote_storage\nFROM snowflake.account_usage.query_history\nWHERE start_time &gt;= DATEADD(day, -7, CURRENT_TIMESTAMP())\nORDER BY total_elapsed_time DESC\nLIMIT 10;<\/pre>\n\n\n\n<p>Look for patterns in poor-performing queries:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Large amounts of data scanned.<\/li>\n\n\n\n<li>Excessive spilling to storage<\/li>\n\n\n\n<li>Long execution times<\/li>\n\n\n\n<li>High credit consumption<\/li>\n<\/ul>\n<\/div>\n\n\n<p>To implement effective query optimization in Snowflake, it requires a combination of:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Strategic table design<\/li>\n\n\n\n<li>Efficient query writing<\/li>\n\n\n\n<li>Understanding of Snowflake&#8217;s query execution mechanics<\/li>\n\n\n\n<li>Continuous monitoring and refinement<\/li>\n<\/ul>\n<\/div>\n\n\n<p>By implementing these techniques, you can significantly reduce query execution time and minimize credit consumption.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-storage-optimization-in-snowflake\"><a id=\"post-104827-_heading=h.z337ya\"><\/a>Storage Optimization in Snowflake<\/h2>\n\n\n\n<p>Managing storage effectively is crucial for both cost control and performance. Let&#8217;s explore key strategies through practical scenarios.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-manage-time-travel-periods\"><a id=\"post-104827-_heading=h.3j2qqm3\"><\/a>Manage Time Travel Periods<\/h3>\n\n\n\n<p>Time Travel allows you to access historical data, but it comes with storage costs. Here&#8217;s how to optimize it:<\/p>\n\n\n\n<p>&#8212; Example: Set 7-day retention for frequently changing tables<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ALTER TABLE sales_data \n     SET DATA_RETENTION_TIME_IN_DAYS = 7; <\/pre>\n\n\n\n<p>&#8212; Example: Reduce retention for large, infrequently accessed tables<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> ALTER TABLE historical_logs \n      SET DATA_RETENTION_TIME_IN_DAYS = 1; <\/pre>\n\n\n\n<p>Management Strategy:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Set longer retention (7+ days) for critical business data.<\/li>\n\n\n\n<li>Use minimal retention (0-1 days) for temporary or staging tables.<\/li>\n\n\n\n<li>Monitor Time Travel storage costs through system views.<\/li>\n\n\n\n<li>Consider business requirements vs. storage costs when setting retention periods.<\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-use-compact-storage-formats\"><a id=\"post-104827-_heading=h.1y810tw\"><\/a>Use Compact Storage Formats<\/h3>\n\n\n\n<p>Compare these approaches to understand storage optimization:<\/p>\n\n\n\n<p>&#8212; Non-optimized table definition<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE TABLE verbose_sales ( \n  date_time TIMESTAMP_NTZ(9), <em>-- More precision than needed<\/em>  \n  product_id VARCHAR(16777216), <em>-- Default max length<\/em> \n  sale_amount NUMBER(38,6) <em>-- Excessive precision<\/em> \n); <\/pre>\n\n\n\n<p>&#8212; Optimized table definition<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE TABLE optimized_sales ( \n  date_time DATE, <em>-- Sufficient for daily sales<\/em> \n  product_id VARCHAR(10), -- Based on actual ID length\n  sale_amount NUMBER(12,2) -- Realistic precision for currency \n);  <\/pre>\n\n\n\n<p><strong>Best practices:<\/strong><\/p>\n\n\n\n<p><strong>Managing Time Travel periods<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Regular audit of retention periods<\/li>\n\n\n\n<li>Set different retention policies based on data importance.<\/li>\n\n\n\n<li>Monitor and adjust based on actual usage patterns.<\/li>\n\n\n\n<li>Consider regulatory requirements.<\/li>\n<\/ul>\n<\/div>\n\n\n<p><strong>Implementing efficient data archival strategies<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Archive infrequently accessed data to lower cost storage<\/li>\n\n\n\n<li>Use clone for zero-copy backup.<\/li>\n\n\n\n<li>Implement staged archival process based on data temperature.<\/li>\n<\/ul>\n<\/div>\n\n\n<p><strong>Using appropriate data types and compression<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Choose minimal but sufficient numeric precision.<\/li>\n\n\n\n<li>Use <code>DATE<\/code> vs <code>TIMESTAMP<\/code> when time isn&#8217;t needed.<\/li>\n\n\n\n<li>Leverage automatic compression features.<\/li>\n<\/ul>\n<\/div>\n\n\n<p><strong>Leveraging zero-copy cloning<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Use for development environments.<\/li>\n\n\n\n<li>Create backup copies without duplicating storage.<\/li>\n\n\n\n<li>Test data modifications safely.<\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-cost-management-framework\"><a id=\"post-104827-_heading=h.4i7ojhp\"><\/a>Cost Management Framework<\/h3>\n\n\n\n<p>Implement proactive cost controls through resource monitors. Here&#8217;s a practical example:<\/p>\n\n\n\n<p>&#8212; Example of resource monitor creation<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE RESOURCE MONITOR monthly_limit\nWITH CREDIT_QUOTA = 1000\n     FREQUENCY = MONTHLY\n     START_TIMESTAMP = IMMEDIATELY\n     TRIGGERS ON 75 PERCENT DO NOTIFY\n              ON 90 PERCENT DO NOTIFY\n              ON 100 PERCENT DO SUSPEND;<\/pre>\n\n\n\n<p>&#8212; Applying resource monitor to warehouse<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ALTER WAREHOUSE COMPUTE_WH\nSET RESOURCE_MONITOR = monthly_limit;<\/pre>\n\n\n\n<p><strong>Implementation strategies with real-world considerations:<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Setting up resource monitors:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Create different monitors for development vs. production.<\/li>\n\n\n\n<li>Set appropriate thresholds based on historical usage.<\/li>\n\n\n\n<li>Consider business hours vs. off-hours requirements.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li>Implementing tagging for cost allocation:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Tag resources by department.<\/li>\n\n\n\n<li>Track project-specific usage.<\/li>\n\n\n\n<li>Enable chargeback mechanisms.<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li>Establishing monitoring and alerting:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Define alert recipients by role.<\/li>\n\n\n\n<li>Set up escalation paths.<\/li>\n\n\n\n<li>Configure notification channels (email, Slack, etc.)<\/li>\n<\/ul>\n<\/div><\/li>\n\n\n\n<li>Creating cost governance policies:<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Document cost management procedures.<\/li>\n\n\n\n<li>Define approval processes for quota increases.<\/li>\n\n\n\n<li>Establish regular review cycles.<\/li>\n<\/ul>\n<\/div><\/li>\n<\/ul>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"h-snowflake-monitoring-and-governance-best-practices\"><a id=\"post-104827-_heading=h.2xcytpi\"><\/a>Snowflake Monitoring and Governance Best Practices<\/h2>\n\n\n\n<p>Like any computer system, it is important to monitor a Snowflake system to make sure that it is running properly. And for a cloud based system like Snowflake, it is even more crucial to make sure you are not using unnecessary resorces.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-monitor-query-and-warehouse-usage\"><a id=\"post-104827-_heading=h.1ci93xb\"><\/a>Monitor Query and Warehouse Usage<\/h3>\n\n\n\n<p>Track query execution times and credit usage:<\/p>\n\n\n\n<p>Here&#8217;s a monitoring query with example results:<\/p>\n\n\n\n<p><em>&#8212; Example query for monitoring warehouse usage<\/em><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">SELECT \nwarehouse_name, \nCOUNT(*) as query_count, \nAVG(execution_time) as avg_execution_time, \nSUM(credits_used) as total_credits \nFROM snowflake.account_usage.query_history \nWHERE start_time &gt;= dateadd('day', -7, current_timestamp()) \nGROUP BY 1 \nORDER BY 3 DESC; <\/pre>\n\n\n\n<p><em>&#8212; Sample Results:<\/em><\/p>\n\n\n\n<p><code>-- ANALYTICS_WH | 1500 queries | 45.2s avg | 250.5 credits <\/code><\/p>\n\n\n\n<p><code>-- ETL_WH | 300 queries | 180.5s avg | 425.8 credits <\/code><\/p>\n\n\n\n<p><code>-- DEV_WH | 800 queries | 15.3s avg | 85.2 credits<\/code><\/p>\n\n\n\n<p><strong>Look for patterns such as:<\/strong><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Unusually long execution times<\/li>\n\n\n\n<li>Unexpected credit consumption<\/li>\n\n\n\n<li>Query patterns outside business hours.<\/li>\n\n\n\n<li>Warehouse sizing mismatches<\/li>\n<\/ul>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-implementation-of-alerts\"><a id=\"post-104827-_heading=h.3whwml4\"><\/a>Implementation of Alerts<\/h3>\n\n\n\n<p>Create a comprehensive alerting system that notifies appropriate teams:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CREATE OR REPLACE PROCEDURE SEND_ALERT( \nWAREHOUSE_NAME STRING, \nCREDIT_USAGE NUMBER, \nALERT_LEVEL STRING,\n RECIPIENT_ROLE STRING ) \nRETURNS STRING \nLANGUAGE JAVASCRIPT \nAS \n$$ \n\/\/ Alert routing based on severity and role\n let recipients = {\n 'DBA': ['dba@company.com'], \n'Finance': ['<a href=\"mailto:finance@company.com\">finance@company.com<\/a>'],\n 'DevOps': ['devops@company.com'] \n};\n \/\/ Alert message customization \nlet message = `Alert Level: ${ALERT_LEVEL} \nWarehouse: ${WAREHOUSE_NAME} \nCredit Usage: ${CREDIT_USAGE} \nTime: ${new Date().toISOString()\n}`; \n\/\/ Send to appropriate channel based on role\n\/\/ Add your notification logic here $$;<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-conclusion\"><a id=\"post-104827-_heading=h.2bn6wsx\"><\/a><strong>Conclusion<\/strong><\/h2>\n\n\n\n<p>Optimizing Snowflake for performance and cost efficiency requires a combination of query optimization techniques, storage management, warehouse optimization and cost governance strategies. By implementing these methods, businesses can achieve significant cost savings while improving query execution times. Start applying these strategies today to unlock the full potential of your Snowflake data warehouse.<\/p>\n\n\n\n<p>Remember that optimization is an iterative process &#8211; monitor, adjust, and refine your strategies based on actual usage patterns and business needs. Start with the highest-impact areas for your organization and gradually implement more sophisticated optimizations as needed.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In today\u2019s data-driven enterprise environment, businesses increasingly rely on Snowflake\u2019s cloud data warehouse for handling large-scale data analytics and storage needs. However, optimizing Snowflake performance is crucial to manage growing data warehouse costs and maintain efficiency. This guide shares actionable strategies for reducing Snowflake expenses while boosting query performance and scalability. Snowflake offers many benefits,&#8230;&hellip;<\/p>\n","protected":false},"author":345259,"featured_media":104837,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,159001],"tags":[],"coauthors":[159232],"class_list":["post-104827","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-featured","category-snowflake"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/104827","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/345259"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=104827"}],"version-history":[{"count":10,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/104827\/revisions"}],"predecessor-version":[{"id":104841,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/104827\/revisions\/104841"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media\/104837"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=104827"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=104827"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=104827"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=104827"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}