MySQL之SQL优化系列(二)

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

序言

使用的数据库依然是mysql示例库sakila
接着上篇的MySQL之SQL优化系列(一)
当通过慢查询日志定位到执行效率较低的SQL之后,使用explain进行低效SQL的分析。

使用EXPLAIN分析低效SQL的执行计划

使用EXPLAIN可以获取MySQL是如何执行SELECT语句的,包括在SELECT语句执行过程中表如何连接以及连接的顺序,如下示例SQL执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
mysql> explain select sum(amount) from customer a,payment b where 1=1 and a.customer_id = b.customer_id and email='JANE.BENNETT@sakilacustomer.org'\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: 599
filtered: 10.00
Extra: Using where
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: b
partitions: NULL
type: ref
possible_keys: idx_fk_customer_id
key: idx_fk_customer_id
key_len: 2
ref: sakila.a.customer_id
rows: 26
filtered: 100.00
Extra: NULL
2 rows in set, 1 warning (0.01 sec)

字段解释:

  • select_type:表示select的类型,常见取值有SIMPLE(简单表,不使用表连接或子查询)、PRIMARY(主查询,外层的查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(子查询中的第一个SELECT)
  • table:输出结果集的表
  • type:表示MySQL在表中找到所需行的方法,或者称为访问类型,常见的有:
    1
    ALL —— index —— range —— ref —— eq_ref —— const,system —— NULL
    从做到右,性能由最差到最好。示例:
  1. type=ALL,全表扫描,MySQL遍历全表来找到匹配行:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mysql> explain select * from film limit 1\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: film
    partitions: NULL
    type: ALL
    possible_keys: NULL
    key: NULL
    key_len: NULL
    ref: NULL
    rows: 1000
    filtered: 100.00
    Extra: NULL
    1 row in set, 1 warning (0.00 sec)
  2. type=index,索引全扫描,MySQL遍历整个索引来查询匹配的行:
    1
    mysql> show index from film;
    获取得到film表的索引:film_id(主键),title,language_id,original_language_id
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mysql>  explain select title from film\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: film
    partitions: NULL
    type: index
    possible_keys: NULL
    key: idx_title
    key_len: 767
    ref: NULL
    rows: 1000
    filtered: 100.00
    Extra: Using index
    1 row in set, 1 warning (0.00 sec)
  3. type=range,索引范围扫描,常见的有between,>,<等。
  4. type=ref,使用非唯一索引扫描或唯一索引的前缀扫描,返回匹配单独值得记录行,例如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mysql> explain select * from payment where customer_id=24\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: payment
    partitions: NULL
    type: ref
    possible_keys: idx_fk_customer_id
    key: idx_fk_customer_id
    key_len: 2
    ref: const
    rows: 25
    filtered: 100.00
    Extra: NULL
    1 row in set, 1 warning (0.00 sec)
    索引idx_fk_customer_id是非唯一索引,查询条件为等值查询条件customer_id=24,所以扫描索引的类型为ref。ref还经常出现在join操作中。
  5. type=eq_ref,类似ref,区别在于使用的索引是唯一索引,对于每一个索引的键值,表中只有一条记录匹配。换句换说,就是在进行多表连接时,使用得失primary key或者unique index作为关联条件。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    mysql> explain select * from film a,film_text b where a.film_id = b.film_id\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: b
    partitions: NULL
    type: ALL
    possible_keys: PRIMARY
    key: NULL
    key_len: NULL
    ref: NULL
    rows: 1000
    filtered: 100.00
    Extra: NULL
    *************************** 2. row ***************************
    id: 1
    select_type: SIMPLE
    table: a
    partitions: NULL
    type: eq_ref
    possible_keys: PRIMARY
    key: PRIMARY
    key_len: 2
    ref: sakila.b.film_id
    rows: 1
    filtered: 100.00
    Extra: Using where
    2 rows in set, 1 warning (0.00 sec)
  6. type=const/system,表单中有最多一个匹配行,查询起来非常迅速,所以这个匹配行中的其他列的值可以被优化器在当前查询中当做常量来处理,例如,根据主键primary key或者唯一索引unique index进行的查询。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    alter table customer add unique index uk_email(email);
    mysql> explain select * from (select * from customer where email='LINDA.WILLIAMS@sakilacustomer.org') a\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: customer
    partitions: NULL
    type: const
    possible_keys: uk_email
    key: uk_email
    key_len: 153
    ref: const
    rows: 1
    filtered: 100.00
    Extra: NULL
    1 row in set, 1 warning (0.00 sec)
    通过唯一索引uk_email访问的时候,类型type为const。
  • possible_keys:表示查询时可能使用的索引
  • key:表示实际使用的索引
  • key_len:使用到索引字段的长度、
  • rows:扫描行的数量
  • Extra:执行情况的说明和描述,包含不适合在其他列中显示但是对执行计划非常重要的额外信息。
文章目录
  1. 序言
  2. 使用EXPLAIN分析低效SQL的执行计划
|