SQL Notes
Learn how to read and understand SQL execution plans using EXPLAIN, identify performance bottlenecks, and use execution plans to optimize your queries.
When you write a SQL query, you tell the database what data you want. But you do not tell it how to get that data. The database's query optimizer figures out the best strategy — should it use an index? Which index? Should it scan the whole table? How should it join the tables? The execution plan reveals all these decisions.
An execution plan is a step-by-step roadmap showing exactly how the database engine will execute your query. Reading execution plans is the single most important skill for SQL performance tuning. It turns you from someone who guesses at performance problems into someone who can diagnose them precisely.
How to View an Execution Plan
MySQL — EXPLAIN
EXPLAIN SELECT * FROM Employees WHERE Department = 'Engineering';Output:
| id | select_type | table | type | possible_keys | key | rows | Extra |
|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | Employees | ref | idx_dept | idx_dept | 45 | NULL |
MySQL — EXPLAIN ANALYZE (Actual execution)
EXPLAIN ANALYZE SELECT * FROM Employees WHERE Department = 'Engineering';This actually runs the query and shows real timing information.
PostgreSQL — EXPLAIN
EXPLAIN SELECT * FROM Employees WHERE Department = 'Engineering';PostgreSQL — EXPLAIN ANALYZE
EXPLAIN ANALYZE SELECT * FROM Employees WHERE Department = 'Engineering';| Index Cond | (department = 'Engineering') |
| Planning Time | 0.085 ms |
| Execution Time | 0.112 ms |
SQL Server — Execution Plan
-- Show estimated plan
SET SHOWPLAN_ALL ON;
GO
SELECT * FROM Employees WHERE Department = 'Engineering';
GO
SET SHOWPLAN_ALL OFF;
-- Or use the graphical plan in SSMS:
-- Click "Include Actual Execution Plan" button, then run the queryKey Operations in Execution Plans
Table Scan (Full Table Scan)
The database reads every single row in the table. This is the slowest operation for large tables:
This means: no useful index exists for your WHERE condition. The database has no choice but to check every row.
Index Seek
The database uses an index to jump directly to the matching rows. This is the fastest lookup:
This means: an index exists and the optimizer used it to find rows efficiently.
Index Scan
The database reads the entire index (but not the full table). Faster than a table scan but slower than an index seek:
This happens when the optimizer decides reading the index is cheaper than the table, but cannot seek to specific rows.
Nested Loop Join
For each row in the outer table, search for matches in the inner table. Good for small datasets:
Hash Join
Builds a hash table from one input, then probes it with the other. Good for large datasets:
Sort
Explicitly sorts data, usually for ORDER BY or to prepare for a merge join:
Reading a MySQL EXPLAIN Output
EXPLAIN SELECT e.Name, d.DeptName, e.Salary
FROM Employees e
JOIN Departments d ON e.DeptID = d.DeptID
WHERE e.Salary > 50000
ORDER BY e.Salary DESC;| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | e | range | idx_salary | 5000 | Using where; Using filesort |
| 1 | SIMPLE | d | eq_ref | PRIMARY | 1 | NULL |
Interpretation:
- e table: Uses
idx_salarywith a range scan to find employees with salary > 50000. "Using filesort" means it needs an extra sort for ORDER BY. - d table: Uses PRIMARY key with eq_ref (single row lookup per employee). Very efficient.
Common Performance Indicators
| What You See | What It Means | Action |
|---|---|---|
| Table Scan / Full Scan | No index used | Add an index on the WHERE column |
| Using filesort | Extra sort needed | Add an index that matches ORDER BY |
| Using temporary | Temp table created | Simplify GROUP BY or add composite index |
| rows = very high number | Many rows examined | Filter is not selective enough, add index |
| type = ALL | Full table scan | Worst case, add appropriate index |
| type = ref or eq_ref | Index used efficiently | Good performance |
| type = range | Index range scan | Good for BETWEEN, >, < queries |
Real-World Example: Diagnosing a Slow Query
-- This query is slow (takes 8 seconds on 2 million orders)
SELECT c.Name, COUNT(o.OrderID) AS OrderCount, SUM(o.Amount) AS TotalSpent
FROM Customers c
JOIN Orders o ON c.CustomerID = o.CustomerID
WHERE o.OrderDate >= '2026-01-01'
GROUP BY c.Name
ORDER BY TotalSpent DESC
LIMIT 10;Run EXPLAIN:
EXPLAIN SELECT c.Name, COUNT(o.OrderID), SUM(o.Amount)
FROM Customers c JOIN Orders o ON c.CustomerID = o.CustomerID
WHERE o.OrderDate >= '2026-01-01'
GROUP BY c.Name ORDER BY SUM(o.Amount) DESC LIMIT 10;If the plan shows a full table scan on Orders, add an index:
CREATE INDEX idx_order_date_customer ON Orders (OrderDate, CustomerID, Amount);Run EXPLAIN again — the plan should now show an Index Range Scan instead of a Full Table Scan, and the query runs in milliseconds.
Real-World Example: Missing Index Detection
EXPLAIN SELECT * FROM Products WHERE Category = 'Electronics' AND Brand = 'Samsung';If the plan shows:
This means no index helps this query. Create one:
CREATE INDEX idx_prod_cat_brand ON Products (Category, Brand);New plan:
Performance improvement: from scanning 500,000 rows to reading 150 rows directly.
Tips for Reading Execution Plans
- Look for full table scans — these are your biggest performance killers
- Check the rows column — high numbers mean the database examines too many rows
- Look for "Using filesort" — this means an extra sorting pass is needed
- Check join types — eq_ref and ref are good; ALL is bad
- Compare estimated vs actual — use EXPLAIN ANALYZE for real numbers
- Read from inside out — inner operations execute first
Common Mistakes to Avoid
Mistake 1: Never looking at execution plans. Many developers write queries and never check how they execute. Always EXPLAIN slow queries.
Mistake 2: Trusting row estimates blindly. Estimated row counts can be wrong if table statistics are outdated. Run ANALYZE TABLE to update statistics.
Mistake 3: Optimizing queries that are already fast. Focus on queries that actually cause problems. A query running once daily at 2 seconds is not worth optimizing over one running 10,000 times daily at 500ms.
Mistake 4: Adding indexes without checking the plan. Sometimes the optimizer ignores your index because it determined a full scan is actually faster for that specific query.
Best Practices
- EXPLAIN every slow query before attempting to optimize it
- Use EXPLAIN ANALYZE for actual timing information
- Keep table statistics updated with ANALYZE TABLE
- Look at the biggest cost first — optimize the most expensive operation
- Test with production-like data — plans change based on data volume
- Compare plans before and after adding indexes to verify improvement
Execution plans are your window into the database engine's decision-making process. Learning to read them transforms SQL performance tuning from guesswork into science. Whenever a query is slow, EXPLAIN is always your first step.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for SQL Execution Plans.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this SQL Complete Guide topic.
Search Terms
sql-complete-guide, sql complete guide, sql, complete, guide, optimization, execution, plan
Related SQL Complete Guide Topics