二、MySQL优化之explain执行计划type和possible_key与key的属性

explain之type:访问类型

八种访问类型:system、const、eq_ref、ref、range、index、all、null

最好到最差的顺序:system>const>eq_ref>ref>range>index>all

最全的访问顺序:system>const>eq_ref>ref>fulltext>ref_or_null>index_merge> unique_subquery>index_subquery>range>index>all

在项目使用中 至少优化到range和ref

  1. type之system:系统类型

表只有一行记录,等于系统表,这是常量const类型的特例

  1. type之const:常量类型

常量,表示通过索引一次就找到了所查询的一条数据,
const用于此比较primary key(主键)或者unique(唯一)索引
因为只匹配一行数据所以查询很快
如将主键置于where列表中,mysql就能将该查询转换成一个常量

mysql> EXPLAIN SELECT * FROM( SELECT * FROM t1 WHERE id = 3 ) tmp1;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
|  1 | PRIMARY     | <derived2> | system | NULL          | NULL    | NULL    | NULL  |    1 | NULL  |
|  2 | DERIVED     | t1         | const  | PRIMARY       | PRIMARY | 4       | const |    1 | NULL  |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+

t1 表访问类型是const常量,主键id在where列表中
最外层的select是临时表,只有一条数据所以是system类型

  1. type之eq_ref:唯一或者主键索引查询

唯一索引扫描,对于每个索引建,
表中只有一条数据匹配,常见于主键或唯一索引扫描
使用索引查询,查询到的数据只有一条

mysql> explain select * from t1,t2 where t1.id = t2.id ;
+----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref        | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+
|  1 | SIMPLE      | t2    | ALL    | PRIMARY       | NULL    | NULL    | NULL       |    1 | NULL  |
|  1 | SIMPLE      | t1    | eq_ref | PRIMARY       | PRIMARY | 4       | demo.t2.id |    1 | NULL  |
+----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+

t1使用主键查询,只查询到一条数据,type是eq_ref
注意:t1与t2关联之后查出一条数据,type才会等于eq_ref

  1. type之ref:where条件精确查询

非唯一索引扫描,返回匹配某个单独值得所有行
本质上也是一种索引访问,他返回所有匹配某个单独值得行
然而可能会找到多个符合条件的数据,所以他应该属于查找和扫描的混合体
匹配某个单独值得所有行,
组合索引,使用非全索引的字段去查询
查看索引:show index from t1;
创建索引(如果没有)create index inx_idcard_tel on t1 (id_card,tel)

mysql> explain SELECT * FROM t1 WHERE t1.id_card = '622421'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ref
possible_keys: inx_idcard_tel
          key: inx_idcard_tel
      key_len: 57
          ref: const
         rows: 1
        Extra: Using index condition

使用组合索引中的非全索引字段查询数据,type为ref
注意:这里不能单独使用tel字段查询,索引会失效

  1. type之range:where范围查询

只检索指定范围的行,使用一个索引来进行选择行,key列显示使用了哪个字段的索引
一般就是在where语句中出现了between and 、>、<、in 等范围的查询条件
这种范围扫索引比全部索引扫描好一些,它只需要开始于索引的某个点,而结束语另一点,不用扫描全部索引

mysql> explain select * from t1 where t1.id between 1 and 10\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 4
        Extra: Using where

还有以下范围查询语句
    explain SELECT * FROM t1 WHERE t1.id>1
    explain SELECT * FROM t1 WHERE t1.id in(1,2);
  1. type之index:全索引扫描

全索引扫描,是从索引中扫描全表

mysql> explain select id FROM t1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: index
possible_keys: NULL
          key: inx_idcard_tel
      key_len: 93
          ref: NULL
         rows: 4
        Extra: Using index

这里是查询列中使用了主键索引,type=index

  1. type之all:全表扫描

全表扫描,将遍历全表以找到匹配的行

mysql> explain select * FROM t1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 4
        Extra: NULL

防止使用*导致全表扫描

explain之possible_key与key:可能使用的索引和实际使用的索引

possible_key:显示可能应用到这张表的索引,一个或者多个,查询涉及到的字段上若存在索引,则该索引被列出,但不一定被查询实际使用

key:实际使用到的索引,如果为null,则没有使用索引,查询中如果使用了覆盖索引,则该索引仅出现在key列表中

覆盖索引:查询列表中的字段要被所建的索引覆盖(小于等于)

  • 情况一:理论上没有使用索引但实际上使用
mysql> explain select id FROM t1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: index
possible_keys: NULL
          key: inx_idcard_tel
      key_len: 93
          ref: NULL
         rows: 4
        Extra: Using index

possible_keys=null理论上没有使用索引
key=inx_idcard_tel实际上使用了组合索引
注意:这里使用到了覆盖索引的概念

  • 情况二:理论上使用了索引但实际没有使用
mysql> explain select * from t1 where id_card=62  and tel='156'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ALL
possible_keys: inx_idcard_tel
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 4
        Extra: Using where

possible_keys=inx_idcard_tel理论上使用了索引
key=null实际上索引失效了,id_card是varchar类型,数值转字符串,导致索引失效
注意:varchar类型字段的数值必须使用单引号,防止索引失效

  • 情况三:理论和实际上都没有使用索引
mysql> explain select * from t1 where tel='156'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 4
        Extra: Using where

possible_keys=null理论上没有使用索引
key=null实际也没有使用
注意:组合索引的最左侧索引缺失,导致其他索引失效

  • 情况四:理论和实际上都使用了索引
mysql> explain select * from t1 where id_card = '156' and tel='123'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ref
possible_keys: inx_idcard_tel
          key: inx_idcard_tel
      key_len: 93
          ref: const,const
         rows: 1
        Extra: Using index condition

mysql> explain select * from t1 where id_card = '156'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ref
possible_keys: inx_idcard_tel
          key: inx_idcard_tel
      key_len: 57
          ref: const
         rows: 1
        Extra: Using index condition

理论和实际都使用了组合索引,
通过key_len可以判断出使用组合索引的单索引id_card
因为id_card和tel都使用了之后key_len=93

写在最后

人这一生也没有多少时间可以挥霍,
踏实一点,务实一些,
做自己想做的事,
如此简单!

你可能感兴趣的:(MySQL)