沃梦达 / IT编程 / 数据库 / 正文

Mysql通过explain分析定位数据库性能问题

当我们在使用Mysql数据库时,会遇到一些性能问题,例如查询速度慢等,这时就需要通过explain分析定位数据库性能问题。

当我们在使用Mysql数据库时,会遇到一些性能问题,例如查询速度慢等,这时就需要通过explain分析定位数据库性能问题。

下面是Mysql通过explain分析定位数据库性能问题的完整攻略:

1. 查看查询语句的执行计划

在查询语句前加上"explain"关键字,就可以查看该查询语句的执行计划。执行计划是Mysql优化器生成的一种树形结构,用于描述查询所需要的操作步骤。

例如,我们要查找用户表中id为1的记录:

explain select * from user where id=1;

执行结果如下:

+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| 1  | SIMPLE      | user  | NULL       | ref  | PRIMARY       | PRIMARY | 4       | const| 1    | 100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+

从执行结果中我们可以看到,该查询使用了索引(possible_keys和key列均为PRIMARY)进行检索,扫描了1行(rows列),过滤条件是id=1。

2. 分析执行计划

分析执行计划,可以发现查询语句是否存在慢查询、瓶颈等问题。根据执行计划的分析,可以优化查询语句,提升查询性能。

2.1 select_type

select_type表示查询类型,重要性从下到上逐渐增加。常见的select_type类型有:SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION、UNION RESULT等。例如,上面的查询语句的select_type是SIMPLE,表示这是最简单的查询类型。

2.2 table

table表示查询的数据表。如果查询涉及多个表,这里会显示当前被优化的表。

2.3 partitions

partitions表示匹配的分区,如果表没有被分区,它的值为NULL。

2.4 type

type表示访问类型,是性能分析中最重要的一个指标。常见的访问类型有:ALL、index、range、ref、eq_ref、const、system、NULL等。例如,上面的查询语句的type为ref,表示使用了索引。

2.5 possible_keys

possible_keys表示可能用到哪些索引,这个值是一个列表,表示查询中可能用到的索引。

2.6 key

key表示实际使用的索引,如果为NULL,则没有使用索引。例如,上面的查询语句的key为PRIMARY,表示使用了主键。

2.7 key_len

key_len表示索引中使用的字节数。

2.8 ref

ref表示此列要查找的值的来源。例如,上面的查询语句的ref为const,表示使用常量值查找。

2.9 rows

rows表示扫描的行数。例如,上面的查询语句的rows为1,表示扫描了1行。

2.10 Extra

Extra表示额外的信息,常见的有Using filesort、Using temporary、Using index等。例如,上面的查询语句的Extra为NULL。

示例1

假设有一个user表,其中有1000条数据,现在要查询id在500到600之间且name为'张三'的记录,代码如下:

select * from user where id>=500 and id<=600 and name='张三';

执行结果如下:

+----+-------------+-------+------------+-------+---------------+--------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key    | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+--------+---------+-------+------+----------+-------------+
| 1  | SIMPLE      | user  | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL  | 101  | 5.00     | Using where |
+----+-------------+-------+------------+-------+---------------+--------+---------+-------+------+----------+-------------+

从执行计划中可以看到,查询使用了range访问类型,使用了PRIMARY索引,扫描了101行,行数多于期望,需要优化查询。

可以考虑使用联合索引,优化查询语句:

create index idx_id_name on user(id, name);

查询语句优化后的结果:

+----+-------------+-------+------------+-------+---------------+-----------+---------+-------------+------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key       | key_len | ref         | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+-----------+---------+-------------+------+----------+--------------------------+
| 1  | SIMPLE      | user  | NULL       | ref   | idx_id_name   | idx_id_name | 98      | const,const | 1    | 100.00   | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+-----------+---------+-------------+------+----------+--------------------------+

优化后的查询语句使用了联合索引,扫描行数变为1,查询性能得到了提升。

示例2

假设有一个order表,其中有10000条数据,现在要查询2019年11月份的订单列表,代码如下:

select * from order where datediff(create_time, '2019-11-01')>=0 and datediff(create_time, '2019-12-01')<0;

执行结果如下:

+----+-------------+--------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra       |
+----+-------------+--------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| 1  | SIMPLE      | order  | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 10000 | 50.00    | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+-------+----------+-------------+

从执行计划中可以看到,查询类型为ALL,没有使用索引,扫描了10000行,行数较多,需要优化查询。

可以考虑使用日期索引,提升查询性能:

alter table order add index idx_create_time(create_time);

优化后的查询语句:

select * from order where create_time between '2019-11-01' and '2019-11-30 23:59:59'; 

执行结果如下:

+----+-------------+--------+------------+-------+---------------+------------------+---------+------------+------+----------+--------------------------+
| id | select_type | table  | partitions | type  | possible_keys | key              | key_len | ref        | rows | filtered | Extra                    |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------------+------+----------+--------------------------+
| 1  | SIMPLE      | order  | NULL       | range | idx_create_time| idx_create_time  | 5       | const      | 838  | 100.00   | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------------+------+----------+--------------------------+

优化后的查询语句使用了日期索引,扫描行数变为838,查询性能得到了提升。

通过以上两个示例,我们可以看到,使用explain分析查询语句的执行计划,能够帮助我们定位数据库性能问题,并能够优化查询语句,提升查询性能。

本文标题为:Mysql通过explain分析定位数据库性能问题