注: 该SQL语句全部是针对于本地MySQL上的mysqlsenior数据库的 s1,s2表
实例所用表的介绍
s1 表:
CREATE TABLE `s1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key1` varchar(100) DEFAULT NULL,
`key2` int(11) DEFAULT NULL,
`key3` varchar(100) DEFAULT NULL,
`key_part1` varchar(100) DEFAULT NULL,
`key_part2` varchar(100) DEFAULT NULL,
`key_part3` varchar(100) DEFAULT NULL,
`common_field` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`), 主键索引
UNIQUE KEY `idx_key2` (`key2`), 唯一性索引
KEY `idx_key1` (`key1`),
KEY `idx_key3` (`key3`), 普通索引
KEY `idx_key_part` (`key_part1`,`key_part2`,`key_part3`) 联合索引
) ENGINE=InnoDB AUTO_INCREMENT=20002 DEFAULT CHARSET=utf8
s2 表:
CREATE TABLE `s2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key1` varchar(100) DEFAULT NULL,
`key2` int(11) DEFAULT NULL,
`key3` varchar(100) DEFAULT NULL,
`key_part1` varchar(100) DEFAULT NULL,
`key_part2` varchar(100) DEFAULT NULL,
`key_part3` varchar(100) DEFAULT NULL,
`common_field` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`), 主键索引
UNIQUE KEY `idx_key2` (`key2`), 唯一性索引
KEY `idx_key1` (`key1`),
KEY `idx_key3` (`key3`), 普通索引
KEY `idx_key_part` (`key_part1`,`key_part2`,`key_part3`) 联合索引
) ENGINE=InnoDB AUTO_INCREMENT=20002 DEFAULT CHARSET=utf8
Id:
作用:
1: 标识 select 关键字,SQL语句中每写一个 select 就会有一个新的 id
2:表示表加载的顺序
(1):如果id相同,那么加载表的顺序就是从上至下
(2):id值不同。id值越大的表,对应的优先级越高,越先被执行,如子查询
应用举例:
(1): explain select * from s1 inner join s2 on s1.key1 = s2.key1 where s1.common_field = 'a' ;
SQL中只有一个 select,所以 id 只有 1。 s1 在上,说明 s1表先加载,s2后加载 因为 s1是主动表,s2是从动表
(2): explain select * from s1 where s1.key1 in ( select key3 from s2) ;
子查询,肯定是先查询 s2 表,根据 s2 表的结果查询 s1表
Select_type:
作用:
一个查询SQL中可能包含多个小查询,每一个小查询都有一个 select_type 属性
表示当前小查询在整个查询SQL中扮演什么角色
应用举例:
(1): explain select * from s1 union select * from s2;
Union关键字会把两个表的结果联合起来,组成一个临时表
外层的查询 select_type = primary ,内层的查询 select_type = union
(2): explain select * from s1 where s1.key1 in ( select key3 from s2) ;
Type:
情况一:type = null ; 根本不需要用到表:
explain select now();
情况二:
type = const; 用到了主键、唯一性索引 ,且查询的数据只有一条
select * from s1 where id = 18645;
explain select * from s1 where s1.key2 = 12136 ;
情况三:
type = eq_ref; 用到了主键索引,但却是关联查询
explain select * from s1 inner join s2 on s1.id = s2.id ;
注: 因为 s1 表是要全部扫描的,所以走全表查询
扫完一条 s1 中的数据就根据s1的id 去匹配 s2 中的 id 字段
相当于 s2 中依旧是走的主键索引,但是整体是一个联表查询,所以 type = eq_ref
情况四:
type = ref 用到了非主键索引,查询数据只有一条
select * from s1 where s1.key1 = 'bmicNI';
情况五:
type = range; 用到了索引,但是查询的数据是一个范围
explain select * from s1 where id > 15000 and id < 15100;
情况六:
type = index; 查询用到了索引,但是查询索引的全部,
explain select id from s1;
情况七:
type = all; 全表查询,没用到索引
select * from s1;
注:关于全表查询和使用索引查询
主键索引中,最后一层的叶子节点存储了该表中的所有数据,并且所有的叶子节点组成了一个链表
如果查询时,是从该链表头开始查询,依次向后遍历,那么就叫做全表查询
如果查询时,是从索引节点开始查询,从而找到叶子节点,那么就叫索引查询
Key:
Possible_keys: 表示可能使用的索引
key:表示真实使用的索引
key_len:表示使用索引长度
具体:看上面案例
rows:表示预估的要扫描的记录数
Extra:
情况一:no tables use
没有对任何表进行扫描: explain select now();
情况二:impossible where
表示 where 后面的条件是根本不成立的 explain select * from s1 where 1 != 1;
情况三:using where
表示查询根本没有用到索引 explain select * from s1 where common_field = 'a';
情况四:null
表示我们正常使用索引 explain select * from s1 where key1 = ' a ' ;
情况五:using index
我们使用了覆盖索引,即:不用回表操作 explain select id,key1 from s1 where key1 = ' a ';
情况六:联表查询
从动表采用索引,主动表无索引
explain select * from s1 inner join s2 on s1.key1 = s2.key1;
情况七: using join buffer
表示使用了 join buffer 内存块
explain select * from s1 inner join s2 on s1.common_field = s2.common_field;
我们通过该 SQL 语句发现,该联表操作 从动表 没有任何的索引,只能全表扫描
MySQL为了加快速度,分配一块名叫`join buffer`的内存块
情况八:using union
使用了两个索引 explain select * from s1 where id = 16544 or key1 = 'a';
情况九:using filesort
在内存或磁盘中排序,无法利用 B+Tree 索引排序
explain select * from s1 order by common_field = 'a';
情况十:using temporary
使用临时表 explain select key1 from key1 union select key1 from s2;