当我们在使用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分析定位数据库性能问题 - Python技术站