The Explain abstract

The Explain keyword is a common keyword for SQL optimization in Mysql. It is usually used to “view the execution plan of SQL instead of executing SQL”, so as to quickly find out the problem of SQL.

Create the required “user table user, role table role, and user role relationship table ROLE_USER” as test tables before explaining:

/ / the user tableDROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `name` varchar(25) DEFAULT NULL,
 `age` int(11) NOT NULL DEFAULT 0,  `update_time` datetime DEFAULT NULL,  PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  INSERT INTO `user` (`id`, `name`, `age`,`update_time`) VALUES (1,'Joe', 23,'the 2020-12-22 15:27:18'), (2,'bill', 24,'the 2020-06-21 15:27:18'), (3,'Cathy', 25,'the 2020-07-20 15:27:18');  DROP TABLE IF EXISTS `role`; CREATE TABLE `role` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(10) DEFAULT NULL,  PRIMARY KEY (`id`),  KEY `index_name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  INSERT INTO `role` (`id`, `name`) VALUES (1,'Product Manager'), (2,'Technical Manager'), (3,'Project Director');  DROP TABLE IF EXISTS `role_user`; CREATE TABLE `role_user` (  `id` int(11) NOT NULL,  `role_id` int(11) NOT NULL,  `user_id` int(11) NOT NULL,  PRIMARY KEY (`id`),  KEY `index_role_user_id` (`role_id`,`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  INSERT INTO ` role_user ` (` id `, ` role_id `, ` user_id `) VALUES (1, 2, 1), (2,1,2), (3) filling;Copy the code

Let’s start with an SQL:explain select * from user where id =2;, you can see the following results:As you can see, there are 12 fields and they all have corresponding values. This is the explain execution plan. If you can understand this execution plan, you are not far from being proficient in SQL optimization.

Id field

Id indicates the sequence number of the SELECT query statement. It identifies the order in which the SQL is executed. The SQL is executed from the largest to the smallest by ID.

What does that mean? For example, run the SQL: explain select * from user where id in (select user_id from role_user);

+----+-------------+-----------+------------+-------+---------------+--------------------+---------+------+------+------ ----+-----------------------------------------------------------------------------------+| id | select_type | table     | partitions | type  | possible_keys | key                | key_len | ref  | rows | filtered | Extra                                                                             |
+----+-------------+-----------+------------+-------+---------------+--------------------+---------+------+------+------ ----+-----------------------------------------------------------------------------------+| | 1 SIMPLE | user | NULL | | ALL PRIMARY | NULL | NULL | NULL | 3 | | NULL | 100.00|  1 | SIMPLE      | role_user | NULL       | index | NULL          | index_role_user_id | 8       | NULL |    3 |    33.33 | Using where; Using index; FirstMatch(user); Using join buffer (Block Nested Loop) |
+----+-------------+-----------+------------+-------+---------------+--------------------+---------+------+------+------ ----+-----------------------------------------------------------------------------------+Copy the code

The first entry corresponds to the USER table, and the second entry corresponds to the ROLE_USER table, in which case the ID is the same.

If the id is different, for example, run the following SQL: explain select (select 1 from user limit 1) from role; :

+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+------- ------+| id | select_type | table | partitions | type  | possible_keys | key        | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+------- ------+|  1 | PRIMARY     | role  | NULL       | index | NULL          | index_name | 33      | NULL |    3 |   100.00 | Using index |
| 2 | SUBQUERY | user | NULL | index | NULL | PRIMARY 100.00 | | | NULL | 3 | 4 Using the index |+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+------- ------+Copy the code

Mysql > select * from user where id=2; mysql > select * from user where id=2; mysql > select * from user where id=2;

“Conclusion:” this is the ID to identify the order of SQL execution. Generally, there will be multiple records in complex queries. Simple queries have only one record. Subqueries are optimized in Mysql 8, so sometimes even complex queries only have one record.

Select_type field

Select_type specifies the query type, that is, whether the query corresponds to a simple query or a complex query. If the query is complex, the query contains simple subquery, from clause subquery, and union query. Here’s a look at all the query types in select_Type separately.

simple

simpleIndicates a simple query, without any complex query.

PRIMARY

In a complex queryThe outermost select statement has the query type PRIMARYFor example, execute the following SQL:explain select * from role where id = (select id from role_user where role_id = (select id from user where id = 2)); Select, which is the outermost layerSelect * from role where id =?Will be marked as PRIMARY.

SUBQUERY

inSubqueries contained in select or WHERETheta is going to be represented by thetaSUBQUERYType, for example, the SQL executed in the previous sentence has two subqueries as SUBQUERY.

DERIVED

DERIVED stands for DERIVED table, or DERIVED table, and is represented as a DERIVED type in a subquery containing fromMysql performs these subqueries recursively and puts the results in temporary tables. Execute SQL:Explain select * from (select name from user union select name from role) a where a.name = '三'; It has been optimized and added in Mysql 5.7 and abovederived_merge(Derived merge), can speed up query efficiency.

UNION

In the event of aIn the UNION query, the second select query is represented as UNION:

UNION RESULT

The RESULT of the UNION query statement is marked as a UNION RESULTSQL > execute SQLExplain select * from (select name from user union select name from role) a where a.name = '三'; As you can see from the table field in the fourth row, the records in the fourth row come from the second and third rows3 > < union2,, so the result of a UNION query is marked asUNION RESULT

other

The seven select_types above are all more common, and a few less common, just to get an idea:

  1. DEPENDENT UNION: also represents the second or subsequent statement in the UNION query, but depends on the external query.
  2. DEPENDENT SUBQUERYThe first SELECT statement in the: subquery also depends on external queries.
  3. UNCACHEABLE SUBQUERYThe result of the: subquery cannot be cached and the first line of the outer join must be reevaluated.

The table field

One is an existing table. For example, the user and role above are all tables created by ourselves, and can also represent derived tables.

For example, the table field of UNION RESULT is represented as

, i.e. the RESULT records of the second and third rows are queried.
,3>

The type field

The type field represents the type of the SQL association or access. From this field we can determine the SQL lookup database table, the search records of the approximate range is what, directly reflects the efficiency of SQL problems.

System, const, eq_ref, ref, range, index, ALL. System > const > eq_ref > ref > range > index > ALL.

system

System is a special case of const, “indicating that there is only one row in the table.”

const

Const means that the data is found through the index onceUse equivalent queries in unique or primary key indexesBecause there is only one data match in the table, the lookup is very fast. Example:explain select * from user where id =2;

eq_ref

Eq_ref indicates that a unique index or primary key index scan is used as a table link matching condition. For each index key, only one record in the table matches it. Such as:explain select * from user left join role_user on user.id = role_user.user_id left join role on role_user.role_id=role.id;

ref

Ref performance is worse than eq_REF, and it also indicates the link matching conditions of the table, that is, which table fields are used as the values of the query index column. The difference between REF and Eq_REF is that eq_REF uses a unique index or primary key index.

The result of a REF scan may find multiple rows that match the criteria, essentially an index access that returns matching rows. Such as:Explain select * from user where name = 'explain ';

range

Range uses an index to retrieve rows in a given range. Range is usually found when a query statement such as BETWEEN, <>, or IN is used after where:explain select * from user where id > 2;

index

Index indicates that the index tree will be traversed. Index avoids ALL faster, but if the index appears, you need to check whether the index is used correctly:explain select id from user;

ALL

The difference between ALL and index is that ALL is read from the hard disk, while index is read from the index fileSQL > select * from top to bottom; SQL > select * from top to bottom; SQL > select * from top to bottom;explain select * from user;

Possible_keys field

Possible_keys specifies possible indexes that can be used in the possible_keys query. The possible_keys is not necessarily used.

If the index is not NULL, it indicates that the index needs to be added to optimize the query. If the database feels that the full table scan is faster, it may also be NULL.

The key fields

The key field differs from possible_keys in that possible_keys contains the value of key.

To enable Mysql to USE or IGNORE the possible_keys INDEX, you can USE FORCE INDEX, USE INDEX, or IGNORE INDEX.

Key_len field

Indicates the number of bytes used by the index in the SQL query. The number of bytes is not the actual length, but calculated by calculating the length of the index used in the query. The maximum possible length of the index field is displayed.

In general, key_len should be as small as possible without losing precision. For example, the above test table id is int, int consists of 4 bytes:explain select * from user where id =2; Key_len has its own rules for different types, as shown below:

The data type Number of bytes
string Char (n) : Indicates the length of n bytes

Varchar (n) : 2 bytes the value is a string of 3n + 2 bytes if it is utf-8
Numeric types Tinyint: 1 byte

Smallint: 2 bytes

Int: 4 bytes

Bigint: 8 bytes
Time to type Date: 3 bytes

Timestamp: 4 bytes

Datetime: 8 bytes

If the index is a string and the actual string is too long to be stored (768 bytes), mysql will use a similar left prefix index.

Ref field

Ref represents the comparison of columns to the index, the matching condition of the table join, and which columns or constants are used to query the value on the index column.

Rows field

Rows represents the estimated number of rows to be scanned. Generally, Mysql estimates the number of rows to be scanned for the search record based on the statistics table information and index selection. Note that this is not the actual number of rows in the result set.

Partitions, filtered fields

Partitions represent matched partitions; Filtered represents the percentage of queried table rows in a table.

Extra fields

This field displays additional information about the SQL query in the following cases:

Using index

The column to be queried is overwritten by the index. This indicates that the query performance is high, that is, the information to be queried can be found in the index, and the index is used correctly.explain select id from user where id =2; If using WHERE is also present, the index is used to perform a lookup of the index key value. If using WHERE is not present, it indicates that the index is used to read data rather than perform the action of the query.

Using where

In contrast to Using index, the query column is not covered by the index. The where condition is followed by a non-index leading column, which simply uses the WHERE condition:explain select user.* from user,role,role_user where user.id = role_user.user_id and role.id=role_user.role_id;

Using temporary

Using temporary Indicates that a temporary table is used to store intermediate results. Temporary tables are used when sorting results, for example, sort order by and group by. Example:Explain select * from (select name from user union select name from role) a where a.name = '三';

Using filesort

Mysql uses an external index to sort data and does not use an index in a table:explain select * from user order by name;

Using join buffer

Using join buffer means to use the join buffer:explain select user.* from user,role,role_user where user.id = role_user.user_id and role.id=role_user.role_id; It emphasizes that the intermediate results are stored in the join buffer instead of the index when the join condition is obtained, and that the presence of this value generally indicates that an index needs to be added for optimization.

Impossible where

Impossible where occurs when the condition after where is always false. This can be ignored and is less common:explain select * from user where name = 'hah' and name = 'sfsd';

Select tables optimized away

Explain select min(id) from user;There are other attributes in the Extra field, but almost none of them have been seen, so they do not appear, so I will explain them. If you are interested, you can learn about them by yourself. Only these common attributes are listed here.

Say so many theories always want to practice, the following to the user test table for example to test practice.

practice

(1) Through queryExplain select * from user where name =' explain ';The name field does not create an index.

We can solve this problem by creating a federated index index_name_age_time:

alter table user add index index_name_age_time (name,age,update_time) ;
Copy the code

When the next query is made, the index is used:(2) Use of federated indexes to followLeftmost prefix ruleBefore, I wrote a detailed article on the use of the left-most prefix rule principle. You can refer to [].

EXPLAIN SELECT * FROM user WHERE name = ‘aaa ‘; SELECT * FROM user WHERE name =’ aaa ‘;

EXPLAIN SELECT * FROM employees WHERE left(name,2) = ‘3 ‘; , causing index invalidation.

(4) do not use (! = <>); is not null; is not null;