This document provides an introduction to using EXPLAIN to analyze MySQL queries. It begins with background on MySQL and the objectives of learning to use EXPLAIN. It then covers the syntax of EXPLAIN, the output it provides, and what each column in the output means. The document concludes with brief discussions on indexing techniques and query optimization.
2. <Insert Picture Here>
Intro to MySQL EXPLAIN
Ligaya Turmelle
Senior Technical Support Engineer MySQL
http://joind.in/2257
Friday, October 29, 2010
3. MySQL Basics
MySQL is the world's most popular open source database
software, with over 100 million copies of its software downloaded
or distributed throughout its history.
a key part of LAMP (Linux, Apache, MySQL, PHP / Perl / Python),
the fast-growing open source enterprise software stack.
Site: http://www.mysql.com/
Download: mysql.org or http://dev.mysql.com/downloads/
Online Manual: http://dev.mysql.com/doc/refman/5.1/en/index.html
Friday, October 29, 2010
4. Objectives
So what are we hoping you will learn
How to get EXPLAIN output
How to read the output of EXPLAIN
What does it mean? What can we do to speed things up?
Briefly discuss indexing techniques
Briefly discuss query optimization techniques
Friday, October 29, 2010
5. Start at the beginning
Syntax: EXPLAIN [EXTENDED] SELECT select_options
Basically you just put an EXPLAIN before a SELECT
statement.
What does EXPLAIN do?
displays information from the optimizer about the query
execution plan.
EXTENDED with SHOW WARNINGS
Works only with SELECT statements
Some statements can be converted to SELECTS but the
statement has to touch all the same columns
Friday, October 29, 2010
6. Output
mysql> EXPLAIN SELECT c.Name FROM City c WHERE
District='Florida'G
** 1. row ****
id: 1
select_type: SIMPLE
table: c
type: ref
possible_keys: District
key: District
key_len: 20
ref: const
rows: 15
Extra: Using where
1 row in set (0.00 sec)
Friday, October 29, 2010
7. EXPLAIN Output
Each row provides information about one table
EXPLAIN output columns:
id key_len
select_type ref
table rows
type Filtered (new to 5.1)
possible_keys Extra
key
Friday, October 29, 2010
9. id
The SELECT identifier.
Only if there are subqueries, derived tables or unions
is this incremented
Derived table is a subquery in the FROM clause that created
a temporary table
Number reflects the order that the SELECT was done
in
mysql> EXPLAIN SELECT * FROM (SELECT * FROM COUNTRY) AS Country1 LIMIT 5;
+----+-------------+------------+------+---------------+------+---------
| id | select_type | table | type | possible_keys | key | key_len
+----+-------------+------------+------+---------------+------+---------
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL
| 2 | DERIVED | COUNTRY | ALL | NULL | NULL | NULL
+----+-------------+------------+------+---------------+------+---------
Friday, October 29, 2010
10. select_type
The type of SELECT
Can have lots of values and each means something
different
SIMPLE normal SELECT
PRIMARY outermost SELECT
DERIVED - subquery in the FROM clause that is placed in a
temporary table (table is derived from the subquery).
UNION second or more SELECT statement in a UNION
SUBQUERY a SELECT that is not in the FROM clause
UNION and SUBQUERY can have DEPENDANT if they
use the outer SELECT.
Friday, October 29, 2010
11. table
Displays the name or alias of the table used
Read it down and you see the order of the tables in a
JOIN which may or may not be the same as the order
given in the query.
Derived tables will be noted and numbered in the
listing
mysql> EXPLAIN SELECT * FROM (SELECT * FROM COUNTRY) AS Country1 LIMIT 5;
+----+-------------+------------+------+---------------+------+---------
| id | select_type | table | type | possible_keys | key | key_len
+----+-------------+------------+------+---------------+------+---------
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL
| 2 | DERIVED | COUNTRY | ALL | NULL | NULL | NULL
+----+-------------+------------+------+---------------+------+---------
2 rows in set (0.02 sec)
Friday, October 29, 2010
12. type
The access type for the SELECT query
Various methods:
PREFERENCES SELECT TYPE
BEST system/const
eq_ref
ref
ref_or_null
index_merge
range
index
WORST ALL
Friday, October 29, 2010
14. system/const
Best types
system
From an in memory table
Has only one row of data
const
optimizer knows that it can get at most one row from the
table.
Primary key or unique key
mysql> EXPLAIN SELECT * FROM Country WHERE Code='USA';
+----+-------------+---------+-------+---------------+---------+---------
| id | select_type | table | type | possible_keys | key | key_len
+----+-------------+---------+-------+---------------+---------+---------
| 1 | SIMPLE | Country | const | PRIMARY | PRIMARY | 3
+----+-------------+---------+-------+---------------+---------+---------
Friday, October 29, 2010
15. eq_ref
An index lookup that will only return one row
Only used if both conditions are met
All parts of a key are used by the JOIN
Table contains unique, non-nullable key to JOIN on
mysql> EXPLAIN SELECT Country.name FROM Country
-> JOIN City ON City.CountryCode = Country.Code;
+----+-------------+---------+--------+---------------+---------+---------
| id | select_type | table | type | possible_keys | key | key_len |
+----+-------------+---------+--------+---------------+---------+---------
| 1 | SIMPLE | City | ALL | NULL | NULL | NULL
| 1 | SIMPLE | Country | eq_ref | PRIMARY | PRIMARY | 3 |
+----+-------------+---------+--------+---------------+---------+---------
Friday, October 29, 2010
16. ref
Similar to eq_ref but it can return more then one row
Selected when
Either leftmost part of a unique key is used
OR
A non-unique or non-null key is used
mysql> ALTER TABLE City ADD INDEX (district);
Query OK, 4079 rows affected (0.09 sec)Records: 4079 Duplicates: 0
mysql> EXPLAIN SELECT * FROM City WHERE District = 'California';
+----+-------------+-------+------+---------------+----------+--------
| id | select_type | table | type | possible_keys | key | key_len
+----+-------------+-------+------+---------------+----------+--------
| 1 | SIMPLE | City | ref | District | District | 20
+----+-------------+-------+------+---------------+----------+--------
1 row in set (0.01 sec)
Friday, October 29, 2010
17. ref_or_null
Again similar to eq_ref and ref but
Allows null values
OR
Allows null conditions
mysql> ALTER TABLE Country ADD INDEX (IndepYear);
Query OK, 239 rows affected (0.36 sec)Records: 239 Duplicates: 0
mysql> EXPLAIN SELECT IndepYear FROM Country
-> WHERE IndepYear = 1905 or IndepYear IS NULL;
+----+-------------+---------+-------------+---------------+-----------
| id | select_type | table | type | possible_keys | key |
+----+-------------+---------+-------------+---------------+-----------
| 1 | SIMPLE | Country | ref_or_null | IndepYear | IndepYear |
+----+-------------+---------+-------------+---------------+-----------
1 row in set (0.00 sec)
Friday, October 29, 2010
18. index_merge
This is the only access type that allows you to use 2
separate indexes for a table with MySQL
There are lots of rules of when it will be used and in
what conditions intersection, union
http://dev.mysql.com/doc/refman/5.0/en/index-merge-optimization.html
mysql> EXPLAIN SELECT * from City where id = 5 or district = 'Michigan'G
** 1. row **
id: 1
select_type: SIMPLE
table: City
type: index_merge
possible_keys: PRIMARY,District
key: PRIMARY,District
key_len: 4,20
ref: NULL
rows: 9
Extra: Using union(PRIMARY,District); Using where
1 row in set (0.00 sec)
Friday, October 29, 2010
19. range
Access method for a range value in the where clause
(<, <=, >, >=, LIKE, IN or BETWEEN)
With LIKE you can use the range access only if the first
character is not a wild card character
Not possible with hash indexes (MEMORY or NDB tables)
mysql> ALTER TABLE City ADD INDEX (population);
Query OK, 4079 rows affected (0.10 sec) Records: 4079 Duplicates: 0
mysql> EXPLAIN SELECT * FROM City WHERE population>10000000;
+----+-------------+-------+-------+---------------+------------+---------
| id | select_type | table | type | possible_keys | key | key_len
+----+-------------+-------+-------+---------------+------------+---------
| 1 | SIMPLE | City | range | Population | Population | 4
+----+-------------+-------+-------+---------------+------------+---------
Friday, October 29, 2010
20. index
Doing an index scan
Seen when
Getting data is slow...
The data being sought is available through the index
Different then Using index in Extra
mysql> EXPLAIN SELECT id FROM CityG
** 1. row **
id: 1
select_type: SIMPLE
table: City
type: index
possible_keys: NULL
key: PRIMARY
key_len: 4
ref: NULL
rows: 4079
Extra: Using index
1 row in set (0.00 sec)
Friday, October 29, 2010
21. ALL
Full table scan
SLOW
mysql> ALTER TABLE City DROP INDEX Population;
Query OK, 4079 rows affected (0.06 sec)
Records: 4079 Duplicates: 0 Warnings: 0
mysql> EXPLAIN SELECT * FROM City WHERE Population > 10000000G
** 1. row **
id: 1
select_type: SIMPLE
table: City
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4079
Extra: Using where
1 row in set (0.00 sec)
Friday, October 29, 2010
23. possible_keys
Provides a list of the available indexes or NULL that
the optimizer considered for use with the query
Gotcha
If you have tables/column with different character sets, the
indexes on the tables/column may not not be available for
lookup since it has to convert from one character set to
another.
Friday, October 29, 2010
24. key
The actual index that was used for the query or NULL
key and possible_keys are where you start looking at your
indexing strategy
We will briefly discuss optimizing your indexes a bit later in the talk.
mysql> EXPLAIN SELECT id FROM CityG
** 1. row **
id: 1
select_type: SIMPLE
table: City
type: index
possible_keys: NULL
key: PRIMARY
key_len: 4
ref: NULL
rows: 4079
Extra: Using index
1 row in set (0.00 sec)
Friday, October 29, 2010
25. key_len
Shows the number of bytes MySQL will use from the index
You can use this to see if the entire index or part of an index is
being used for the query.
Keep in mind that some character sets can use more then one
byte per character.(Ex: UTF8 can use up to 3 bytes per character)
mysql> EXPLAIN SELECT id FROM CityG
** 1. row *
id: 1
select_type: SIMPLE
table: City
type: index
possible_keys: NULL
key: PRIMARY
key_len: 4
ref: NULL
mysql> DESCRIBE CityG
** 1. row *
Field: ID
Type: int(11) int is 4 bytes
Null: NO
Key: PRI
Default: NULL
Extra: auto_increment
** 2. row *
...
Friday, October 29, 2010
26. ref
Very different from the access type ref
Show which columns or constants within the index
that will be used to access the data
mysql> DESCRIBE SELECT * FROM City WHERE ID=3820G
** 1. row **
id: 1
select_type: SIMPLE
table: City
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra:
1 row in set (0.01 sec)
Friday, October 29, 2010
27. rows
Number of rows MySQL expects to find based on
statistics
Can be very different then what really shows up
You can update these statistics with ANALYZE TABLE
but remember that each storage engine updates it's
statistics with varying levels of accuracy.
Ex: InnoDB statistics are based on 10 random dives rather
then on all the actual data
mysql> EXPLAIN SELECT * FROM City WHERE CountryCode='USA';
+----+-------------+-------+------+---------------+------+---------+------+------+-------
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
+----+-------------+-------+------+---------------+------+---------+------+------+-------
| 1 | SIMPLE | City | ALL | NULL | NULL | NULL | NULL | 4079 | Using
+----+-------------+-------+------+---------------+------+---------+------+------+-------
1 row in set (0.00 sec)
Friday, October 29, 2010
28. filtered
Since 5.1.12
Indicates an estimated percentage of table rows that
will be filtered by the table condition.
Rows shows the estimated number of rows examined
rows filtered / 100 shows the number of rows that will be
joined with previous tables.
Displayed if you use EXPLAIN EXTENDED.
mysql> EXPLAIN extended SELECT * from City where district = 'Michigan';
-------+------+---------------+----------+---------+-------+------+----------+---------
table | type | possible_keys | key | key_len | ref | rows | filtered | Extra
-------+------+---------------+----------+---------+-------+------+----------+---------
City | ref | District | District | 20 | const | 8 | 100.00 | Using
-------+------+---------------+----------+---------+-------+------+----------+---------
Friday, October 29, 2010
29. Extra
This is where all additional information is located
Comments you need know about
Using index - you are using a covering index (getting data
from the index rather then the table)
Using filesort - manual sorting in a temporary table was
done rather then using an index for the sort
Using temporary - at some point in the execution a
temporary table was made. If necessary you want to keep it
in RAM (tmp_table_size and max_heap_table_size)
Using where - filtering outside the storage engine.
Friday, October 29, 2010
31. Indexing
Know your data and queries
You always have to keep the big picture in mind
Data changes and the right index now may not be the right
index later
Understand how indexes work in MySQL
Leftmost prefix
More indexes is not necessarily better
MyISAM vs. InnoDB
ANALYZE TABLE
Friday, October 29, 2010
32. Indexing
(con't)
Shoot for the best EXPLAIN plan
Use indexes for sorting
Covering indexes
Index hinting is possible though highly discouraged
If you know absolutely that you should be using a specific
index _and_ ANALYZE TABLE is not helping
Requires that you maintain that query over time since data
changes (can't set it and forget it)
http://dev.mysql.com/doc/refman/5.1/en/index-hints.html
also look into STRAIGHT_JOIN
Friday, October 29, 2010
34. Query Tuning
Use the slow query log
Don't guess which queries are slow - know!
You can set a maximum time for a query to run and if it goes
over, log it (long_query_time)
In 5.1 micro time is available for under 1 sec
You can tell it to log all queries that do not use indexes
(log_queries_not_using_indexes)
http://dev.mysql.com/doc/refman/5.0/en/slow-query-log.html
Don't be afraid of sub-selects, but use them wisely
Can you write it as a JOIN and if so does it run faster then the
subselect?
Friday, October 29, 2010
35. Query Tuning
(con't)
Be willing to consider alternate methods of doing things
Instead of one big query with lots of derived tables, use a stored
procedure that builds intermittent MEMORY tables that you
index and work with
Use Query Profiling to get the nitty gritty
Available from 5.0
There is a lot of information available using profiling
http://dev.mysql.com/tech-resources/articles/using-new-query-profiler.html
Test, Test, Test
Keep in mind load and concurrency will affect speed
Friday, October 29, 2010