八种访问类型:
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
表只有一行记录,等于系统表,这是常量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类型
唯一索引扫描,对于每个索引建,
表中只有一条数据匹配,常见于主键或唯一索引扫描
使用索引查询,查询到的数据只有一条
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
非唯一索引扫描,返回匹配某个单独值得所有行
本质上也是一种索引访问,他返回所有匹配某个单独值得行
然而可能会找到多个符合条件的数据,所以他应该属于查找和扫描的混合体
匹配某个单独值得所有行,
组合索引,使用非全索引的字段去查询
查看索引: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字段查询,索引会失效
只检索指定范围的行,使用一个索引来进行选择行,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);
全索引扫描,是从索引中扫描全表
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
全表扫描,将遍历全表以找到匹配的行
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
防止使用*导致全表扫描
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
写在最后
人这一生也没有多少时间可以挥霍,
踏实一点,务实一些,
做自己想做的事,
如此简单!