Livro Percona Pratical MySQL Performance Optimization
Livro Percona Pratical MySQL Performance Optimization
QUERY TUNING
As we can see from the previous chapters, MySQL performance
tuning can be critical for business goals and procedures. Query
tuning can have a huge impact. In this chapter we will focus on
optimizing the typical “slow” queries.
INDEXES
Before starting with query tuning we need to talk first about
indexes, and how indexes are implemented in MySQL.
Indexes
Practical MySQL Performance Optimization 5
In this scenario, MySQL will scan through the tree and visit many
leafs/nodes:
Indexes
Practical MySQL Performance Optimization 6
Explain Plan
The main way to “profile” a query with MySQL is to use “explain”.
The set of operations that the optimizer chooses to perform the
most efficient query is called the “query execution plan,” also
known as the “explain plan.” The output below shows an example
of the explain plan.
As we can see from the explain plan, MySQL does not use any
indexes (key: NULL) and will have to perform a full table scan.
Indexes
Practical MySQL Performance Optimization 7
*****************1. row**********************
id: 1
select_type: SIMPLE
table: City
type: ref
possible_keys: Name
key: Name
key_len: 35
ref: const
rows: 1
Extra: Using where
Index Usages
MySQL will choose only one index per query (and per table if
the query joins multiple tables). In some cases, MySQL can also
intersect indexes (we won’t cover that scenario in this section,
however). MySQL uses index statistics to make a decision about
the best possible index.
Combined Indexes
Combined indexes are very important for MySQL query
optimizations. MySQL can use the leftmost part of any index. For
example, if we have this index:
Indexes
Practical MySQL Performance Optimization 8
Note the key_len part shows “3”. This is the number of bytes used
from our index. As the CountryCode field is declared as char(3),
that means that MySQL will use the first field from our combined
index.
Similarly, MySQL can use the two leftmost fields, or all three fields
from the index. In this example, the two leftmost fields are used:
Indexes
Practical MySQL Performance Optimization 9
So MySQL will use the two first fields from the comb key:
»» CountryCode = 3 chars
»» District = 20 chars
»» Total = 23
Whereas in this explain plan, all three fields are used from the
index:
Indexes
Practical MySQL Performance Optimization 10
»» CountryCode = 3 chars/bytes
»» District = 20 chars/bytes
»» Population = 4 bytes (INT)
»» Total = 27
However, if the query does not have the first leftmost part of an
index, MySQL can’t use it:
If you are too tired to do the math for calculating the actual
fields in the index, MySQL 5.6 and 5.7 has a great feature: explain
format=JSON:
Indexes
Practical MySQL Performance Optimization 11
With the JSON format, MySQL shows the list of fields inside the
index that MySQL will use.
Covered Index
The covered index is an index that covers all fields in the query. For
example, for this query:
Indexes
Practical MySQL Performance Optimization 12
The above index uses all fields in the query, in this order:
»» Where part
»» Group By/Order (not used now)
»» Select part (here: name)
Here is an example:
Indexes
Practical MySQL Performance Optimization 13
Indexes
Practical MySQL Performance Optimization 14
Indexes
Queries
Practical MySQL Performance Optimization 16
These queries are usually the slowest ones. We will show how to
optimize these queries and decrease the query response time, as
well as the application performance in general.
As we can see in the output above, MySQL does not use any
indexes (no proper indexes are available), but it also shows “Using
temporary; Using filesort”. MySQL will need to create a temporary
table to satisfy the “Group by” clause if there is no appropriate
index.
Queries
Practical MySQL Performance Optimization 17
(You can find more information about the temporary tables here.)
select max(DepDelayMinutes),
carrier, dayofweek
from ontime_2012
where dayofweek = 7
group by Carrier
Queries
Practical MySQL Performance Optimization 18
...
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4833086
Extra: Using where; Using temporary;
Using filesort
As we can see, MySQL does not use any index and has to scan
~4M rows. In addition, it will have to create a large temporary table.
Creating a “dayofweek” index will only filter out some rows, and
MySQL will still need to create a temporary table:
group by Carrier\G
type: ref
possible_keys: DayOfWeek
key: DayOfWeek
Queries
Practical MySQL Performance Optimization 19
key_len: 2
ref: const
rows: 817258
Extra: Using where; Using temporary;
Using filesort
possible_keys: DayOfWeek,covered
key: covered
key_len: 2
ref: const
rows: 905138
Extra: Using where; Using index
As we can see from the explain, MySQL will use our index and
will avoid creating a temporary table. This is the fastest possible
solution.
Queries
Practical MySQL Performance Optimization 20
Queries
Practical MySQL Performance Optimization 21
where dayofweek = 7
group by Carrier, dayofweek)
For each of the two queries in the union, MySQL will be able to
use an index instead of creating a temporary table, as shown in the
explain plan below:
As we can see, MySQL uses our covered index for each of the two
queries. It will still have to create a temporary table to merge the
results. However, it will probably be a much smaller temporary
table as it will only need to store the result sets of two queries.
Queries
Practical MySQL Performance Optimization 22
KEY loose_index_scan
(Carrier,DayOfWeek,DepDelayMinutes)
Queries
Practical MySQL Performance Optimization 23
table: ontime_2012
type: range
possible_keys: covered
key: loose_index_scan
key_len: 5
ref: NULL
rows: 201
Extra: Using where; Using index for
group-by
“Using index for group-by” in the where clause means that MySQL
will use the loose index scan. A loose index scan is very fast as it
only scans a fraction of the key. It will also work with the range scan:
table: ontime_2012
type: range
possible_keys: covered
key: loose_index_scan
key_len: 5
ref: NULL
rows: 213
Extra: Using where; Using index for
group-by;
Queries
Benchmarks
Practical MySQL Performance Optimization 25
BENCHMARK
Below is a benchmark that compares query speed with a temporary
table, a tight index scan (covered index) and a loose index scan.
The table is six million rows and approximately 2GB in size:
As we can see, the loose index scan index shows the best
performance. Unfortunately, loose index scans only work with
two aggregate functions, “MIN” and “MAX” for the GROUP BY.
“AVG” together with the GROUP BY does not work with a loose
index scan. As we can see below, MySQL will use a covered index
(not loose_index_scan index) and, because we have a range in the
where clause (dayofweek > 5), it will have to create a temporary
table.
Benchmarks
Practical MySQL Performance Optimization 26
table: ontime_2012
type: range
key: covered
key_len: 2
ref: NULL
rows: 2961617
Extra: Using where; Using index; Using
temporary; Using filesort
table: City
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4079
Extra: Using where; Using filesort
Benchmarks
Practical MySQL Performance Optimization 27
table: City
type: ref
key: my_sort2
key_len: 3
ref: const
rows: 207
Extra: Using where
Here’s an example:
Benchmarks
Practical MySQL Performance Optimization 28
type: index
possible_keys: DayOfWeek,covered
key: DepDelayMinutes
key_len: 5
ref: NULL
rows: 24
Extra: Using where
This can be very fast if MySQL finds the rows right away. For
example, if there are a lot of rows matching our condition
(dayofweek in (6,7)), MySQL will find ten rows quickly. However, if
there are no rows matching our condition (i.e., empty result set, all
rows filtered out), MySQL will have to scan the whole table using
an index scan. If we have two indexes, a covered index and an index
on the “ORDER BY” field only, MySQL usually is able to figure out
the best possible index to use.
Benchmarks
Practical MySQL Performance Optimization 29
Benchmarks
Practical MySQL Performance Optimization 30
GROUP BY carrier\G
Results:
16 rows in set (11.98 sec)
Benchmarks
Practical MySQL Performance Optimization 31
Results:
32 rows in set (1 min 57.93 sec)
Benchmarks
Practical MySQL Performance Optimization 32
Benchmarks
Calculated Fields in MySQL 5.7
Practical MySQL Performance Optimization 34
`Flight_dayofweek` tinyint(4)
GENERATED ALWAYS AS (dayofweek(FlightDate))
VIRTUAL,
PRIMARY KEY (`id`),
CONCLUSION
We have discussed different indexing strategies to optimize your
slow queries.
Now you can look again at your MySQL slow query log, and
optimize the slower queries.
Conclusion
How Percona Can Help
Practical MySQL Performance Optimization 39
If you want to put your time and focus on your business, but
still have peace of mind knowing that your database will be
fast, available, resilient and secure, Percona Database Managed
Services may be ideal for you. With Percona Managed Services,
your application performance can be proactively managed by
our team of experts so that problems are identified and resolved
before they impact your business. When you work with Percona’s
Managed Service team you can leverage our deep operational
knowledge of Percona Server for MySQL, Percona Server for
MongoDB, MongoDB, MariaDB®, OpenStack Trove, Google Cloud
SQL and Amazon® RDS to ensure your databases performing at
the highest levels.
ABOUT PERCONA
Copyright © 2016 Percona LLC. All rights reserved. Percona is a registered trademark of Percona LLC. All other trademarks or service marks are property of their respective owners.