Hello! Welcome to your next lesson on Amazon Redshift.
In our last session, we built a strong foundation in securing your Redshift cluster, covering network controls, IAM roles, and encryption. Now that we know how to protect our data warehouse, we'll shift our focus from security to performance, moving from the cluster level to the individual query level.
This lesson directly addresses the learning outcome: Analyze query plans to optimize slow-running queries in Redshift. This is a critical skill for any data engineer. A poorly written query can neutralize the benefits of a well-designed cluster, leading to slow dashboards, missed SLAs for ETL jobs, and increased costs. We will learn how to diagnose these queries and apply targeted fixes.
The Query Optimization Workflow
When a query runs slowly, your goal is to understand why. Is the database doing unnecessary work? Is it moving large amounts of data across the network? The key to answering these questions is the query plan, which is Redshift's step-by-step recipe for executing your SQL.
Our approach will be two-fold:
- Leveraging Automated Tooling: First, we'll explore automated features like Redshift Advisor and Workload Management (WLM) that proactively manage performance.
- Manual Deep Dive with
EXPLAIN: Then, we'll learn to manually generate and interpret a query plan to identify specific bottlenecks like inefficient joins and costly data movements.
1. Automated Performance Management
Before diving into manual analysis, it's essential to use the tools AWS provides. Often, they can identify and even fix common performance issues for you.
Redshift Advisor & Auto Table Optimization
Redshift Advisor is like having an automated DBA on your team. It analyzes your cluster's workload and provides specific, actionable recommendations for improving performance and reducing costs. These recommendations often point to suboptimal table design, such as missing sort keys or inefficient distribution styles.
Taking this a step further, Redshift now offers Auto Table Optimization, which can automatically apply some of these recommendations for you.
Workload Management (WLM) and Query Monitoring Rules (QMR)
Sometimes, a query is slow not because it's written badly, but because it's competing for resources with other queries. Workload Management (WLM) allows you to define queues to prioritize workloads. For example, you can ensure that critical dashboard queries get more resources than a large, ad-hoc analytical query. Automatic WLM simplifies this by managing memory and concurrency for you.
To protect the cluster from rogue queries, you can set up Query Monitoring Rules (QMR). These rules can automatically terminate or deprioritize queries that exceed certain thresholds, like running for too long or scanning too much data.
The following video from AWS re:Invent provides a great overview of these features.
AWS re:Invent 2020: Deep dive on best practices for Amazon Redshift
To understand how Redshift's automated features help manage performance, please watch these selected clips from the 'Deep dive on best practices for Amazon Redshift' talk.
Please watch the following two segments: Redshift Advisor and Auto Table Optimization (07:29 - 08:38): Focus on how Advisor generates recommendations and how Auto Table Optimization can implement them automatically. Workload Management and QMR (17:07 - 21:40): Pay attention to how WLM prioritizes workloads and how QMR can act as a safeguard against poorly performing queries.
2. Deep Dive: The EXPLAIN Command
When automated tools aren't enough, you need to roll up your sleeves and analyze the query plan yourself. You can generate this plan by prefixing your query with the EXPLAIN command.
EXPLAIN doesn't run the query; it just shows you the plan the optimizer has chosen. This plan details the sequence of operations, the join algorithms, and the data movement required to get the final result.
Understanding Parallel Execution
Redshift is a Massively Parallel Processing (MPP) system. A query is broken down into segments and streams that run in parallel across the cluster's compute nodes. Understanding this is key to reading a plan.

How to Read a Query Plan
A query plan can look intimidating, but the approach is straightforward:
- Read from the inside out: The most indented operations happen first.
- Read from the bottom up: The flow of execution generally moves from the bottom of the plan to the top.
- Look for the highest
cost: The plan includes cost estimates for each step. Start your analysis by focusing on the most expensive operations, as they offer the greatest potential for improvement.
This article provides a practical guide to reading and understanding the structure of a query plan.
Please read the following article from the AWS documentation. It provides the official guide to analyzing a query plan and is a critical reference for this topic.
Read the entire page. Focus on the general steps for analysis and the specific things to look for: join types, high-cost sorts, and broadcast operators. Keep this page open as a reference for the next section.
3. Deconstructing the Plan: Common Bottlenecks and Fixes
Now let's break down the most critical parts of the query plan, what they mean, and how to address the problems they might reveal. We'll use another resource to provide more narrative explanations.
Amazon Redshift deep dive (Part 3): Understanding Query plans
This blog post, 'Amazon Redshift deep dive (Part 3): Understanding Query plans', offers excellent, intuitive explanations of the key plan operators. We will refer to it as we break down the components.
Read the sections 'EXPLAIN Joins' and 'EXPLAIN Data Distribution'. They provide great context for the technical details in the AWS documentation you just read.
Based on these resources, here are the three main areas to investigate in a query plan:
A. Join Operations
Joins are often the most expensive part of a query. The optimizer's choice of join algorithm has a massive impact on performance.
-
Nested LoopJoin:- What it means: This is a brute-force join, comparing every row from the outer table to every row of the inner table. It's the least efficient join type, with a complexity that can be quadratic.
- Why it happens: Often occurs when there is no join condition (a
CROSS JOIN) or when using inequality conditions (<,>). - What to do: Avoid cross joins on large tables if at all possible. This is a major red flag in a query plan.
-
Hash Join:- What it means: The optimizer builds an in-memory hash table on the smaller (inner) table and then scans the larger (outer) table to find matches. This is much more efficient than a nested loop.
- Why it happens: This is the most common join type when the tables are not perfectly optimized for joining.
- What to do: This is generally acceptable. However, ensure statistics are up-to-date with
ANALYZEso the optimizer correctly identifies the smaller table to build the hash table.
-
Merge Join:- What it means: This is the fastest join type. It requires both tables to be pre-sorted on the join keys. The database can then read both tables in sorted order and simply "merge" them together.
- Why it happens: This occurs when the join columns are also the
SORTKEYandDISTKEYfor the tables.
- What to do: This is the ideal state. If your most critical and frequent join is a
Hash Join, consider changing your table DDL to use the join columns as distribution and sort keys to enable aMerge Join.
B. Data Distribution (Network Movement)
In an MPP database, network cost is a silent killer. Moving data between compute nodes is extremely expensive. The query plan tells you exactly what data movement is happening.
-
DS_DIST_NONE:- What it means: No data movement is needed. The joining rows are already on the same compute nodes (
collocated). - What to do: This is the best-case scenario. It happens when tables are joined on their
DISTKEY.
- What it means: No data movement is needed. The joining rows are already on the same compute nodes (
-
DS_BCAST_INNER(Broadcast):- What it means: The entire inner table is copied and sent to every compute node.
- Why it happens: The optimizer does this when one table is small.
- What to do: This is efficient if the inner table is small (e.g., a small dimension table). If you see this on a large table, it's a major performance problem. The fix is to change the small table's distribution style to
DISTSTYLE ALL, which permanently stores a copy on every node, avoiding the broadcast during query execution.
-
DS_DIST_BOTH(Redistribution):- What it means: This is the worst-case scenario. Neither table is distributed on the join key, so both tables must be shuffled across the network to collocate the joining rows.
- What to do: If you see this on a frequent, expensive join, you should change the table DDL. Set the
DISTSTYLEtoKEYand use the join column as theDISTKEYfor both tables.
C. Sort Operations
Sort:- What it means: The database has to perform an explicit, costly sort operation.
- Why it happens: This is required for
ORDER BYclauses, someGROUP BYoperations, and to prepare for aMerge Joinif the data isn't already sorted. - What to do: If a
Sortis consistently happening on a column used in aWHEREclause or aJOIN, consider adding that column as aSORTKEYto the table. This allows the query optimizer to take advantage of the pre-sorted data and potentially skip the sort step. Pre-sorting also dramatically improves scan performance by allowing Redshift to use its zone maps to skip large blocks of data that don't contain relevant values.
Test your understanding!
You are analyzing the query plan for a slow query that joins a large fact table, sales (100 million rows), with a small dimension table, stores (200 rows). The plan shows the following step:
XN Hash Join DS_BCAST_INNER (cost=20.50..543210.98 rows=123456 width=120)-> XN Seq Scan on sales ...
Later in the plan, you see that sales is the broadcasted inner table. What is the problem here, and what is the most likely cause and solution?
Show answer
- Problem: The query plan is broadcasting the large
salestable (DS_BCAST_INNER), which is extremely inefficient and will cause massive network traffic. - Cause: The query optimizer has incorrectly identified the huge
salestable as the "inner" or smaller table for the join. This almost always happens when table statistics are stale or missing. The optimizer thinkssalesis small andstoresis large. - Solution: The immediate fix is to run
ANALYZE sales;andANALYZE stores;. After updating the statistics, the optimizer will correctly identifystoresas the inner table and broadcast it instead, which is a very efficient operation for a small dimension table.
Conclusion
In this lesson, you've learned a systematic process for troubleshooting and optimizing slow-running queries in Amazon Redshift. This is a powerful skill that allows you to directly impact the performance and efficiency of your data warehouse.
Key Takeaways:
- Always start with automated tools like Redshift Advisor and ensure WLM is configured to manage your workload.
- For manual tuning, use the
EXPLAINcommand to get the query plan. - Read plans from the bottom up, focusing on the highest-cost operations first.
- Analyze join types: aim for
Merge Join, be okay withHash Join, and be very concerned aboutNested Loop. - Analyze data distribution: aim for
DS_DIST_NONE, avoid broadcasting large tables (DS_BCAST_INNER), and fixDS_DIST_BOTHimmediately by setting a commonDISTKEY. - Look for expensive
Sortoperations and eliminate them by defining an appropriateSORTKEYon your table.
Next Up:
We have now completed our module on data warehousing with Amazon Redshift. We've covered cluster design, loading data, optimizing performance, and securing the environment. In the next module, we'll shift our focus to the data lake itself. Our first lesson will be on how to optimize Athena queries using partitioning, bucketing, and compression, applying some similar principles of performance tuning to a serverless, interactive query environment.