Databases 14 min read

Master MySQL Performance: Using EXPLAIN & EXPLAIN ANALYZE to Optimize Queries

Learn how to leverage MySQL's EXPLAIN and EXPLAIN ANALYZE commands to diagnose query performance, understand each column of the output, choose appropriate indexes, and apply practical optimization steps—including multi‑column indexes—to dramatically reduce row scans and speed up queries.

Senior Brother's Insights
Senior Brother's Insights
Senior Brother's Insights
Master MySQL Performance: Using EXPLAIN & EXPLAIN ANALYZE to Optimize Queries

What Is EXPLAIN and EXPLAIN ANALYZE?

EXPLAIN is a MySQL keyword that shows how the optimizer will execute a query and estimates its cost. EXPLAIN ANALYZE, introduced in MySQL 8.0.18, actually runs the query and prints the real cost of each iterator.

EXPLAIN demo
EXPLAIN demo

Key Columns in EXPLAIN Output

id : identifies the SELECT to which the row belongs.

select_type : indicates whether the SELECT is simple, primary (complex), subquery, UNION, or DELETE.

table : the table accessed at each step.

partition : partitions used (if the table is partitioned).

type : the access type (e.g., const, ref, range, all).

possible_keys : indexes MySQL could use.

key : the index actually chosen.

key_len : length of the chosen index (important for composite indexes).

rows : estimated number of rows examined.

filtered : estimated percentage of rows that satisfy the filter condition.

Extra : additional information such as Using index, Using where, Using temporary, etc.

When to Use EXPLAIN vs. EXPLAIN ANALYZE

Use EXPLAIN when you are unsure whether a query is efficient. If the query is already indexed and partitioned but still runs slowly, switch to EXPLAIN ANALYZE to see actual execution costs. Remember that EXPLAIN ANALYZE runs the query, so avoid it on production data if side‑effects are a concern.

Important Index‑Related Columns

possible_keys : all candidate indexes.

key : the index actually used.

key_len : length of the used index, crucial for composite indexes.

FULLTEXT Indexes and Joins

If a query uses a FULLTEXT index in a JOIN, the select_type column will show FULLTEXT.

Partitions

When a table is partitioned, the partition column lists the partitions accessed. You can force specific partitions with syntax such as SELECT * FROM table_name PARTITION(p1,p2).

Limitations of EXPLAIN

It does not account for triggers, stored functions, or UDFs.

It cannot analyze stored procedures.

It does not show the optimizer’s internal decision process.

Many statistics are estimates and may be inaccurate.

Some values (e.g., filesort vs. Using temporary) are ambiguous.

If EXPLAIN fails to parse a query, you can run SHOW WARNINGS; to get diagnostic hints.

EXPLAIN’s EXTRA Column Values

Using index – a covering index avoids table access.

Using where – rows are filtered after being read from the storage engine.

Using temporary – MySQL creates a temporary table for sorting.

Using filesort – external sort is used instead of index order.

Range checked for each record – indicates missing suitable index.

Using index condition – index condition pushdown before table read.

Backward index scan – descending index scan.

const row not found – the table is empty.

Using index for group‑by – index helps GROUP BY.

Connection Types (type column)

NULL – query resolved at optimization time, no table access.

system – table has zero or one row.

const – matches at most one row (primary key or unique index).

eq_ref – uses a unique index (primary or NOT NULL unique).

ref – uses a non‑unique index with equality comparison.

fulltext – joins using a FULLTEXT index.

index – full index scan (no sorting needed).

range – index range scan.

all – full table scan.

index_merge – combines multiple indexes.

unique_subquery / index_subquery – subquery optimizations.

Practical Optimization Example

Step 1: Run the Initial Query

Using the MySQL sample employees database, run a query that filters by last name and first name:

SELECT * FROM employees WHERE last_name = 'Puppo' AND first_name = 'Kendra';
EXPLAIN demo
EXPLAIN demo

EXPLAIN shows that the query scans 299,733 rows, indicating a performance problem.

Step 2: Optimization Method 1 – Separate Indexes

Creating separate indexes on last_name and first_name allows MySQL to find rows for each column individually, but it cannot efficiently locate the combination last_name='Puppo' AND first_name='Kendra'.

MySQL may use an index‑merge, but this is often less efficient than a single composite index.

Step 3: Optimization Method 2 – Multi‑Column Index

Define a composite index covering both columns:

CREATE INDEX fullnames ON employees(last_name, first_name);

Now run the same SELECT and check with EXPLAIN:

EXPLAIN result
EXPLAIN result

The optimized plan uses the new composite index and accesses only one row, a dramatic improvement over the original 299,733 rows.

Conclusion

MySQL’s EXPLAIN (and EXPLAIN ANALYZE) provide essential insight into how queries are executed. By interpreting the output, choosing appropriate indexes—especially composite indexes—and verifying plans with EXPLAIN, you can significantly boost database performance.

Query OptimizationPerformance TuningMySQLEXPLAIN
Senior Brother's Insights
Written by

Senior Brother's Insights

A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.