MySQL Performance Boosting with Indexes and Explain
Key Points
- Use MySQL's
EXPLAIN
command to analyze and optimize query execution plans, ensuring more efficient database operations by revealing key information such as connection type and index usage. - Implement query analysis to measure the actual running time of a query, thereby performing targeted optimizations to reduce execution time and improve overall performance.
- Add appropriate indexes based on feedback from the
EXPLAIN
command, focusing on the columns used in theWHERE
clause to speed up data retrieval and improve query performance. - For columns involved in search operations, consider using full-text indexing to optimize performance, especially when using the
LIKE
operator in queries. - Note the use of
ORDER BY
in combination withLIMIT
, as it may offset the performance advantages of limiting results, especially if the index is not used effectively.
Database optimization is usually the primary focus in improving application performance and the most common bottleneck. How to measure and understand what needs improvement?
A simple and effective tool is query analysis. Enabling analysis allows more accurate estimates of the run time of a query. This is a two-step process: first, enable analysis; then, call show profiles
to get the query run time.
Suppose the following insertion operation exists in the database (and assuming that user 1 and gallery 1 have been created):
INSERT INTO `homestead`.`images` (`id`, `gallery_id`, `original_filename`, `filename`, `description`) VALUES (1, 1, 'me.jpg', 'me.jpg', 'A photo of me walking down the street'), (2, 1, 'dog.jpg', 'dog.jpg', 'A photo of my dog on the street'), (3, 1, 'cat.jpg', 'cat.jpg', 'A photo of my cat walking down the street'), (4, 1, 'purr.jpg', 'purr.jpg', 'A photo of my cat purring');
A small amount of data will not cause problems, but we can use it for simple analysis. Consider the following query:
SELECT * FROM `homestead`.`images` AS i WHERE i.description LIKE '%street%';
If there are many photo entries, this query may become a problem in the future.
To get the exact run time of this query, you can use the following SQL:
set profiling = 1; SELECT * FROM `homestead`.`images` AS i WHERE i.description LIKE '%street%'; show profiles;
The results are as follows:
Query_Id | Duration | Query |
---|---|---|
1 | 0.00016950 | SHOW WARNINGS |
2 | 0.00039200 | SELECT * FROM homestead.images AS i WHERE i.description LIKE '%street%' LIMIT 0, 1000 |
3 | 0.00037600 | SHOW KEYS FROM homestead.images |
4 | 0.00034625 | SHOW DATABASES LIKE 'homestead' |
5 | 0.00027600 | SHOW TABLES FROM homestead LIKE 'images' |
6 | 0.00024950 | SELECT * FROM homestead.images WHERE 0=1 |
7 | 0.00104300 | SHOW FULL COLUMNS FROM homestead.images LIKE 'id' |
show profiles;
command not only displays the time of the original query, but also the time of all other queries, so that the query can be analyzed accurately.
How to improve query?
You can rely on SQL knowledge to improve, or rely on MySQL's EXPLAIN
command and improve query performance based on actual information.
EXPLAIN
is used to get the query execution plan, that is, how MySQL executes the query. It is suitable for SELECT
, DELETE
, INSERT
, REPLACE
, and UPDATE
statements and displays information about the statement execution plan by the optimizer. The official documentation describes well how EXPLAIN
how
to check if the optimizer joins the tables in the best order.
EXPLAIN
WithEXPLAIN
, you can see which tables you should add indexes so that statements can execute faster by using indexes to find rows. You can also use
EXPLAIN
To give an example to illustrate the use of UserManager.php
, we will use the query to find user emails in
INSERT INTO `homestead`.`images` (`id`, `gallery_id`, `original_filename`, `filename`, `description`) VALUES (1, 1, 'me.jpg', 'me.jpg', 'A photo of me walking down the street'), (2, 1, 'dog.jpg', 'dog.jpg', 'A photo of my dog on the street'), (3, 1, 'cat.jpg', 'cat.jpg', 'A photo of my cat walking down the street'), (4, 1, 'purr.jpg', 'purr.jpg', 'A photo of my cat purring');
EXPLAIN
To use the SELECT
command, just add it before the
SELECT * FROM `homestead`.`images` AS i WHERE i.description LIKE '%street%';
The result is as follows (scroll right to see everything):
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | users | NULL | const | UNIQ_1483A5E9E7927C74 | UNIQ_1483A5E9E7927C74 | 182 | const | 1 | 100.00 | NULL |
These results are not easy to understand at the beginning, let's take a closer look at each one:
id
: This is the sequential identifier for each query inSELECT
.select_type
:SELECT
type of query. This field can take multiple different values, so we will focus on the most important ones:SIMPLE
: Simple query without subqueries or unionsPRIMARY
:select
Located in the outermost query in the connectionDERIVED
:select
is part of the neutron queryfrom
- : The first in the subquery
SUBQUERY
select
- :
UNION
is the second or subsequent statement of the union. The complete list ofselect
field values can be found here.select_type
- : The table referenced by rows.
table
- : This field represents the type of table used by MySQL connection. This is probably the most important field in the
type
output. It can indicate the missing index, or it can show how the query is overridden. Possible values for this field are as follows (sorted from best to worst type):EXPLAIN
- : The table has zero rows or one row.
system
- : There is only one row in the table that matches the row, and the row has been indexed. This is the fastest connection type.
const
- : All parts of the index are used by the join, and the index is
eq_ref
orPRIMARY_KEY
.UNIQUE NOT NULL
- : For each row combination from the previous table, all matching rows of the index column are read. This type of join usually occurs in indexed columns compared using
ref
or operators.=
- : Join the full text index of the table.
fulltext
- : The same as
ref_or_null
, but also contains the rows from the column'sref
value.NULL
- : Connections use index lists to generate result sets. The
index_merge
column ofEXPLAIN
will contain the keys used.KEY
- :
unique_subquery
Subquery returns only one result from the table and uses the primary key.IN
- : Use indexes to find matching rows within a specific range.
range
- : Scan the entire index tree to find matching rows.
index
- : Scan the entire table to find the matching rows for the join. This is the worst type of join, usually indicating a missing appropriate index on the table.
ALL
- : The table has zero rows or one row.
- : Shows the keys that MySQL can use to find rows from a table. These keys may or may not be used in practice.
possible_keys
- : Indicates the index that MySQL actually uses. MySQL always finds the best keys that can be used for queries. When joining multiple tables, it may find some keys that are not listed in
keys
but are better.possible_keys
- : Indicates the length of the index to be used by the query optimizer.
key_len
- : Displays a column or constant that compares to the named index in the
ref
column. rows
: Lists the number of records checked to generate output. This is a very important indicator; the fewer records checked, the better.Extra
: Contains other information. TheUsing filesort
orUsing temporary
equivalent in this column may indicate a query in question.
EXPLAIN
The complete documentation of the output format can be found on the official MySQL page.
Back to our simple query: it is a SIMPLE
type select
with a connection of const
type. This is the best query case we may have. But what happens when we need bigger and more complex queries?
Back to our application mode, we may want to get all the gallery images. We may also want to include only photos with the word "cat" in the description. This is definitely a situation we can find in project requirements. Let's look at the query:
INSERT INTO `homestead`.`images` (`id`, `gallery_id`, `original_filename`, `filename`, `description`) VALUES (1, 1, 'me.jpg', 'me.jpg', 'A photo of me walking down the street'), (2, 1, 'dog.jpg', 'dog.jpg', 'A photo of my dog on the street'), (3, 1, 'cat.jpg', 'cat.jpg', 'A photo of my cat walking down the street'), (4, 1, 'purr.jpg', 'purr.jpg', 'A photo of my cat purring');
In this more complex situation, we should get more information in EXPLAIN
to analyze:
SELECT * FROM `homestead`.`images` AS i WHERE i.description LIKE '%street%';
This will give the following results (scroll right to see all cells):
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | users | NULL | index | PRIMARY,UNIQ_1483A5E9BF396750 | UNIQ_1483A5E9BF396750 | 108 | NULL | 1 | 100.00 | Using index |
1 | SIMPLE | gal | NULL | ref | PRIMARY,UNIQ_F70E6EB7BF396750,IDX_F70E6EB7A76ED395 | UNIQ_1483A5E9BF396750 | 108 | homestead.users.id | 1 | 100.00 | NULL |
1 | SIMPLE | img | NULL | ref | IDX_E01FBE6A4E7AF8F | IDX_E01FBE6A4E7AF8F | 109 | homestead.gal.id | 1 | 25.00 | Using where |
Let's take a closer look and see what we can improve in the query.
As mentioned earlier, the main columns that should be viewed first are the type
columns and rows
columns. The goal should be to get better values in the type
column and minimize the values of the rows
column.
The result of the first query is index
, which is not a good result at all. This means we may be able to improve it.
View our query, there are two ways to solve it. First, the Users
table is not used. We either extend the query to make sure we are targeting the user or we should delete the user portion of the query completely. It only increases the complexity and time of our overall performance.
INSERT INTO `homestead`.`images` (`id`, `gallery_id`, `original_filename`, `filename`, `description`) VALUES (1, 1, 'me.jpg', 'me.jpg', 'A photo of me walking down the street'), (2, 1, 'dog.jpg', 'dog.jpg', 'A photo of my dog on the street'), (3, 1, 'cat.jpg', 'cat.jpg', 'A photo of my cat walking down the street'), (4, 1, 'purr.jpg', 'purr.jpg', 'A photo of my cat purring');
So now we get the exact same result. Let's see EXPLAIN
:
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | gal | NULL | ALL | PRIMARY,UNIQ_1483A5E9BF396750 | NULL | NULL | NULL | 1 | 100.00 | NULL |
1 | SIMPLE | img | NULL | ref | IDX_E01FBE6A4E7AF8F | IDX_E01FBE6A4E7AF8F | 109 | homestead.gal.id | 1 | 25.00 | Using where |
What we are left with is the ALL
type. While ALL
is probably the worst type of connection, there are some cases where it is the only option. According to our requirements, we want all the gallery images, so we need to search the entire galleries
table. When we need all the information in the table, indexes are great when trying to find specific information in the table, but they don't help us. When we encounter this situation, we have to resort to other methods, such as caching.
Since we are working on LIKE
, the last improvement we can make is adding a full text index to our description
field. This way, we can change LIKE
to match()
and improve performance. More information about full-text indexing can be found here.
We also have to check out two very interesting situations: the latest and related features in the application. These apply to gallery and involve some extreme situations that we should pay attention to:
INSERT INTO `homestead`.`images` (`id`, `gallery_id`, `original_filename`, `filename`, `description`) VALUES (1, 1, 'me.jpg', 'me.jpg', 'A photo of me walking down the street'), (2, 1, 'dog.jpg', 'dog.jpg', 'A photo of my dog on the street'), (3, 1, 'cat.jpg', 'cat.jpg', 'A photo of my cat walking down the street'), (4, 1, 'purr.jpg', 'purr.jpg', 'A photo of my cat purring');
The above are related galleries.
SELECT * FROM `homestead`.`images` AS i WHERE i.description LIKE '%street%';
The above is the latest gallery.
At first glance, these queries should be very fast because they use LIMIT
. This is the case in most queries that use LIMIT
. Unfortunately for us and our applications, these queries also use ORDER BY
. Because we need to sort all results before limiting the query, we lose the advantage of using LIMIT
.
Since we know ORDER BY
can be tricky, let's apply our reliable EXPLAIN
.
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | gal | NULL | ALL | IDX_F70E6EB7A76ED395 | NULL | NULL | NULL | 1 | 100.00 | Using where; Using filesort |
1 | SIMPLE | u | NULL | eq_ref | PRIMARY,UNIQ_1483A5E9BF396750 | PRIMARY | 108 | homestead.gal.id | 1 | 100.00 | NULL |
and,
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | gal | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using filesort |
We can see that for both of our queries, we have the worst connection type: ALL
.
Historically, MySQL's implementation, especially when used with ORDER BY
, was often the source of MySQL performance issues. This combination is also used in most interactive applications with large data sets. Features like new registered users and popular tags often use this combination. LIMIT
- Make sure we are using indexes. In our case,
- is a good candidate because it is the field we are sorting. This way we can do
created_at
andORDER BY
without scanning and sorting the complete result set.LIMIT
Sort by columns in the leading table. Generally, if - is sorted by fields that are not the first table in the join order, the index cannot be used.
ORDER BY
Do not sort by expression. Expressions and functions do not allow - to use indexes.
ORDER BY
Pay attention to the large value of - . Large
LIMIT
values will forceLIMIT
to sort more rows. This will affect performance.ORDER BY
and LIMIT
, these are some of the measures we should take to minimize performance issues. ORDER BY
Conclusion
As we have seen, is very useful for identifying problems in queries as early as possible. There are many problems that are only noticed when our application is in production and there are a lot of data or a lot of visitors to access the database. If you can use EXPLAIN
to detect these problems as early as possible, then the possibility of performance problems in the future is much smaller. EXPLAIN
and indexes. EXPLAIN
FAQs about MySQL Performance Indexing (FAQ)
What is the importance of MySQL performance indexing?MySQL performance indexing is crucial to optimize database performance. They significantly speed up data retrieval operations by quickly accessing rows in the data table based on the values in the indexed columns. Without an index, MySQL will have to traverse every row in the table to find the relevant rows, which can be very time-consuming, especially for large databases.
How does the EXPLAIN command help improve MySQL performance?
The
command in MySQL is a powerful tool that provides information about how MySQL performs queries. It shows the order of read tables, the type of read operations performed, the index that can be selected, and the estimated number of rows to be checked. This information can help developers optimize queries and improve database performance. EXPLAIN
Why does MySQL not use any possible keys?
MySQL does not use any possible keys for several reasons. One reason may be that the optimizer estimates that using indexes requires scanning most of the table and decides that table scanning will be faster. Another reason might be that the columns in the WHERE
clause do not match the columns in the index.
How to optimize my MySQL query?
There are several ways to optimize MySQL queries. One way is to use indexes effectively. Indexes can significantly speed up data retrieval. However, they slow down data modification operations such as INSERT
, UPDATE
and DELETE
. Therefore, it is very important to find a balance point. Another way is to use the EXPLAIN
command to understand how MySQL executes queries and finds potential bottlenecks.
What is the difference between primary keys and indexes in MySQL?
The primary key in MySQL is an index. The primary key is a unique identifier for the row in the table. It enforces the uniqueness of a column or column combination and ensures that the column or column combination does not contain NULL
values. On the other hand, an index is a data structure that can increase the speed of data retrieval operations. It can be applied to any column or combination of columns.
How to create an index in MySQL?
You can use the CREATE INDEX
statement to create an index in MySQL. The syntax is as follows: CREATE INDEX index_name ON table_name (column1, column2, …);
. This creates an index on the specified column of the specified table.
What is the composite index in MySQL?
Composite index, also known as multi-column index, is an index containing multiple columns. In MySQL, a composite index can contain up to 16 columns, but the total size of the indexed columns cannot exceed 767 bytes.
How to delete index in MySQL?
You can use the DROP INDEX
statement to delete the index in MySQL. The syntax is as follows: DROP INDEX index_name ON table_name;
. This will delete the specified index from the specified table.
What is the difference between clustered index and nonclustered index in MySQL?
Clustered index determines the physical order of data in the table. Each table can only have one clustered index. On the other hand, nonclustered indexes do not change the physical order of data in the table. Instead, it maintains a separate data structure (index) pointing to the data row, allowing for faster data retrieval.
How to select the index to use in MySQL?
MySQL uses a cost-based optimizer to select the index to use. The optimizer estimates the cost of executing plans for different queries and selects the lowest-cost plan. Cost is estimated based on factors such as the number of rows to be read, the number of disk lookups, CPU cost, and memory usage.
The above is the detailed content of MySQL Performance Boosting with Indexes and Explain. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Alipay PHP...

Session hijacking can be achieved through the following steps: 1. Obtain the session ID, 2. Use the session ID, 3. Keep the session active. The methods to prevent session hijacking in PHP include: 1. Use the session_regenerate_id() function to regenerate the session ID, 2. Store session data through the database, 3. Ensure that all session data is transmitted through HTTPS.

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

The application of SOLID principle in PHP development includes: 1. Single responsibility principle (SRP): Each class is responsible for only one function. 2. Open and close principle (OCP): Changes are achieved through extension rather than modification. 3. Lisch's Substitution Principle (LSP): Subclasses can replace base classes without affecting program accuracy. 4. Interface isolation principle (ISP): Use fine-grained interfaces to avoid dependencies and unused methods. 5. Dependency inversion principle (DIP): High and low-level modules rely on abstraction and are implemented through dependency injection.

How to debug CLI mode in PHPStorm? When developing with PHPStorm, sometimes we need to debug PHP in command line interface (CLI) mode...

How to automatically set the permissions of unixsocket after the system restarts. Every time the system restarts, we need to execute the following command to modify the permissions of unixsocket: sudo...

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

Sending JSON data using PHP's cURL library In PHP development, it is often necessary to interact with external APIs. One of the common ways is to use cURL library to send POST�...
