通过explain分析低效的SQL执行计划

时间:2021-12-25 09:23:11

之前我们讲过如何开启慢查询日志,这个日志的最大作用就是我们通过设定超时阈值,在执行SQL语句中的消耗时间大于这个阈值,将会被记录到慢查询日志里面。DBA通过这个慢查询日志定位到执行缓慢的sql语句,以便来进行优化。那我们今天就来学习一下如何分析抵消的SQL语句。

mysql> explain select* from co3 where ctime=68776 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: co3
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 9471195
filtered: 10.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)

我们主要对三个列说明一下:

select_type:表示SELECT 的类型,常见取值:SIMPLE、PRIMARY、UNION、SUBQUERY

table:输出的结果集的表。

KEY:表示执行语句中使用索引名。

type:表示MySQL在表中找到所需行的方式,或者叫访问类型。这个type的取值是我们重点学习的。主要有以下几个取值:

ALL   |  index  |  range   |  ref   |   eq_ref  |  const,system  |  NULL

从左到右,性能有最差到最好。

1)type=ALL,全表扫描,效率最差。MySQL会遍历全表来找到匹配的行。

mysql> explain select* from co3 where ctime=68776 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: co3
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 9471195
filtered: 10.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)

2)type=index,索引全扫描。MySQL遍历整个索引来查询匹配的行。

mysql> explain select count(*) from co3\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: co3
partitions: NULL
type: index
possible_keys: NULL
key: source_creative_id
key_len: 10
ref: NULL
rows: 9471195
filtered: 100.00
Extra: Using index
1 row in set, 1 warning (0.00 sec)

3)type=range,索引范围扫描,常见于<  <=   >  >=   between等操作符。

mysql> explain select * from co3 where id >= 309 and id <= 500 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: co3
partitions: NULL
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: NULL
rows: 6
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)

4)type=ref,使用非唯一索引扫描或唯一索引的前缀扫描,返回匹配某个单独值的记录行。

mysql> explain select * from co3 where campaign_id=45413\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: co3
partitions: NULL
type: ref
possible_keys: campaign_id
key: campaign_id
key_len: 8
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)

索引campaign_id是非唯一索引,查询条件为等值查询条件,所以扫描索引的类型为ref。ref  也会出现在join操作中。

mysql> explain select * from co3 a,co2 b where a.campaign_id = b.campaign_id\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: a
partitions: NULL
type: ALL
possible_keys: campaign_id
key: NULL
key_len: NULL
ref: NULL
rows: 9471195
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: b
partitions: NULL
type: ref
possible_keys: campaign_id
key: campaign_id
key_len: 8
ref: mob_adn.a.campaign_id
rows: 105
filtered: 100.00
Extra: NULL
2 rows in set, 1 warning (0.00 sec)

5)type=eq_ref,类似于ref,区别在于使用的索引是唯一索引,我们知道唯一索引是unique index 或者是primary key作为关联条件,对于每个索引键值,表中只有一条记录匹配。

mysql> explain select * from co3 a,co2 b where a.id=b.id\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: a
partitions: NULL
type: ALL
possible_keys: PRIMARY
key: NULL
key_len: NULL
ref: NULL
rows: 9471195
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: b
partitions: NULL
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: mob_adn.a.id
rows: 1
filtered: 100.00
Extra: NULL
2 rows in set, 1 warning (0.00 sec)

6)type=const/system,单表中最多有一个匹配行,查询起来非常迅速,所以这个匹配行中的其他列的值可以被优化器在当前查询中当作常量来处理,例如根据主键primary key或者唯一索引unique index进行的查询。

mysql> desc select* from co2 where id=68777845 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: co2
partitions: NULL
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.01 sec)

7)type=NULL,MySQL不用访问表或者索引,直接就能得到结果,例如:

mysql> explain select 1 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
partitions: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
filtered: NULL
Extra: No tables used
1 row in set, 1 warning (0.01 sec)