EXPLAIN in MySQL
The EXPLAIN statement provides information about how MySQL executes a query. It works with SELECT, DELETE, INSERT, REPLACE, and UPDATE statements. Understanding its output is crucial for database optimization.
Key Columns in EXPLAIN Output
| Column | Description |
|---|---|
| id | Sequential identifier for each SELECT within the query. Helps track the order of execution. |
| select_type | The type of SELECT (e.g., SIMPLE, PRIMARY, SUBQUERY, DERIVED, UNION). |
| table | The name of the table the row refers to. Can also be a derived table (e.g., <derivedN>). |
| partitions | The partitions from which records would be matched. |
| type | The join type (how MySQL joins tables). Crucial for performance. |
| possible_keys | Indexes that MySQL could choose from to find rows. |
| key | The index that MySQL actually decided to use. |
| key_len | The length of the chosen key in bytes. Useful for checking if all parts of a composite index are used. |
| ref | Which columns or constants are compared to the index named in the key column. |
| rows | Estimated number of rows MySQL believes it must examine. |
| filtered | Estimated percentage of rows filtered by the table condition. |
| Extra | Additional information about how MySQL resolves the query. |
Detailed Column Explanations
1. id and select_type
- SIMPLE: A simple query without subqueries or unions.
- PRIMARY: The outermost
SELECTin a complex query. - SUBQUERY: A
SELECTin a subquery (not in theFROMclause). - DERIVED: A subquery in the
FROMclause (a "derived table"). - UNION: The second or subsequent
SELECTin aUNION. - DEPENDENT SUBQUERY: A subquery that depends on the outer query (often slow).
- UNCACHEABLE SUBQUERY: A subquery whose result cannot be cached (e.g., uses
RAND()).
2. Join Types (the type column)
Ordered from best to worst performance:
- system: The table has only one row (special case of
const). - const: The table has at most one matching row (e.g., primary key or unique index lookup with constants).
- eq_ref: One row is read from this table for each combination of rows from the previous tables (using a unique index).
- ref: All rows with matching index values are read (using a non-unique index or prefix).
- fulltext: The join is performed using a
FULLTEXTindex. - ref_or_null: Like
ref, but also searches forNULLvalues. - index_merge: Multiple indexes are used and their results merged.
- unique_subquery: For
INsubqueries that return unique results. - range: Only rows in a given range are retrieved using an index (e.g., using
>,<,BETWEEN,IN). - index: Full index scan (better than
ALLbecause the index is usually smaller than the table). - ALL: Full table scan (worst performance).
3. Important "Extra" Values
- Using index: The query is resolved using only the index (Covering Index). No need to read the actual table rows.
- Using where: A
WHEREclause is used to filter rows after fetching them from the storage engine. - Using temporary: MySQL needs to create an internal temporary table to hold the result (common with
GROUP BYorORDER BYon non-indexed columns). Warning sign! - Using filesort: MySQL must do an extra pass to find out how to retrieve the rows in sorted order. Warning sign!
- Select tables optimized away: The optimizer determined that no tables need to be accessed (e.g.,
MIN()on an indexed column). - FirstMatch(table_name): A semi-join optimization that stops searching as soon as the first match is found in a subquery.
Modern MySQL Features (8.0+)
EXPLAIN FORMAT=TREE
Provides a hierarchical, tree-like view of the execution plan. It shows the cost of each operation and the estimated number of rows.
EXPLAIN FORMAT=TREE SELECT ...
EXPLAIN ANALYZE
The most powerful tool for profiling. It actually executes the query and provides:
- Actual time to get the first row and all rows.
- Actual number of rows returned.
- Number of loops (how many times the operation was executed).
EXPLAIN ANALYZE SELECT ...
How to Read EXPLAIN
- Read from top to bottom: MySQL executes the plan in the order shown.
- Check
type: Aim forconst,eq_ref, orref. If you seeALLorindex, consider adding indexes. - Check
rowsandfiltered: Multiplyrows * filteredto see how many rows are passed to the next step. - Watch for
Extrawarnings:Using temporaryandUsing filesortusually mean you need better indexing forGROUP BYorORDER BY. - Use
SHOW WARNINGS: After runningEXPLAIN, runSHOW WARNINGSto see how MySQL rewritten your query.