注意:(针对mysql5.5版本,其他版本可能略有差异)
一、explain关键字解析
1、explain的id和table分析
情景:
要求:查询教sql课程的老师描述
①、sql:
select tc.tcdesc from teacherCard tc,course c,teacher t where c.tid = t.tid and t.tcid = tc.tcid and c.cname = 'sql';
②、使用explain
③、将上述的sql改为子查询
select tc.tcdesc from teacherCard tc where tc.tcid= (select t.tcid from teacher t where t.tid= (select c.tid from course c where c.cname='sql') );
结论:当id不相同时,id越大越先执行,即先c——>t——>tc
④、将上述sql改为多表+子查询的方式
select tc.tcdesc from teacherCard tc,teacher t where t.tcid = tc.tcid and t.tid = (select c.tid from course c where c.cname = 'sql');
结论:当id有相同又有不相同时,先执行id大的,id相同的顺序执行
总结:当id相同时,顺序执行;当id不同时,id大的先执行
2、select_type分析
PRIMARY:包含子查询SQL中的 主查询 (最外层)
SUBQUERY:包含子查询SQL中的 子查询 (非最外层)
simple:简单查询(不包含子查询、union)
derived:衍生查询(使用到了临时表)①、在from子查询中只有一张表
explain select tmp.cname from ( select * from course where tid in (1,2) ) tmp;PRIMARY后面的table为derived2说明其使用衍生表进行查询,其id为2。
②、在from子查询中,如果有table1 union table2,则table1就是derived,table2就是union
explain select cr.cname from ( select * from course where tid = 1 union select * from course where tid = 2 ) cr ;
union:如上例
union result :告知开发人员,那些表之间存在union查询
3、type分析
type的类型:system>const>eq_ref>ref>range>index>all 对type优化的前提是:有索引
①、system:只有一条数据的系统表;或者衍生表只有一条数据的主查询
create table test1( tid int, tname varchar(20) ); insert into test1 values(1,'001'); --增加主键索引 alter table test1 add constraint tid_pk primary key(tid); explain select * from (select * from test1) t where tid = 1;
在primary查询中用到的表t为system。
②、const:仅仅能查到一条数据的SQL,用于Primay key或者unique索引(与索引类型有关)
在存在主键索引的前提下执行: explain select tid from test1 where tid = 1;
删除主键索引,创建普通索引再次执行 alter table test1 drop primary key ; create index test1_index on test1(tid); explain select tid from test1 where tid = 1;
eq_ref唯一性索引,对于每个索引键的查询,返回匹配唯一行数据(有且只有1个,不能多、不能0)
即 通过索引列查出的数据,该索引列的数据唯一不能重复;常见于唯一索引和主键索引
测试:
将表数据恢复一下
给teacherCard的tcid设置主键约束,给teacher的tcid设置唯一约束。
alter table teacherCard add constraint pk_tcid primary key(tcid); alter table teacher add constraint uk_tcid unique index(tcid); explain select t.tcid from teacher t,teacherCard tc where t.tcid = tc.tcid ;
删除teacher后面的几条记录的原因是:如果不删除teacher表中tcid为4,5,6的三条数据是不会查出来的。这样不满足其不能为0的情况。
ref:非唯一性索引,对于每个索引键的查询,返回匹配的所有行(0,多)
测试:
增加数据
为tname增加索引
alter table teacher add index tname_index(tname); explain select * from teacher where tname = 'tz';
小结:根据索引列查询
range:检索指定范围的行,where后面是一个范围查询(between,> < >=,特殊:in可能会时效,当查询的数据量大于一半的时候会转化为ALL)
index:查询全部索引中的数据
explain select tid from teacher ; --tid 是索引, 只需要扫描索引表,不需要所有表中的所有数据
all:查询全部表中的数据
explain select cid from course ; --cid不是索引,需要全表所有,即需要所有表中的所有数据
4、possible_key分析
预测可能用到的索引
5、key分析
实际使用到的索引
6、key_len 分析
索引的长度
char-not null情况
创建一个表 create table test_kl ( name char(20) not null default '' ); --为name设置一个index alter table test_kl add index index_name(name) ; --按刚才的索引查询 explain select * from test_kl where name ='' ;
小结:utf8 1个字符占3个字节
char-null情况
alter table test_kl add column name1 char(20) ; alter table test_kl add index index_name1(name1) ; explain select * from test_kl where name1 ='' ;
小结:如果索引字段可以为null,会使用1个字节用于标识
增加一个复合索引
drop index index_name on test_kl ; drop index index_name1 on test_kl ; 增加一个复合索引 alter table test_kl add index name_name1_index (name,name1) ; explain select * from test_kl where name1 = '' ; --121(如果用到了name1,则一定用了name) explain select * from test_kl where name = '' ; --60
使用varchar的情况:会再用2个额外的字节标识可变长度
7、ref分析
作用: 指明当前表所 参照的 字段。
执行如下语句: explain select * from course c,teacher t where c.tid = t.tid and t.tname = 'tw'; (注意要求c.tid t.tid t.tname为索引列)
小结:第一次查询参照的是tw这个常量,所以为const,第二次查询参照的是t.tid
8、rows分析
被索引优化查询的数据个数(实际通过索引而查询到的数据个数)
9、Extra分析
①、using filesort:性能消耗大;需要额外的一次排序(查询)。常见于order by中
构造表,并创建索引 create table test02 ( a1 char(3), a2 char(3), a3 char(3), index idx_a1(a1), index idx_a2(a2), index idx_a3(a3) ); 分别执行如下语句 explain select * from test02 where a1 = '' order by a2; explain select * from test02 where a1 = '' order by a3; explain select * from test02 where a2 = '' order by a1; explain select * from test02 where a2 = '' order by a3; explain select * from test02 where a3 = '' order by a1; explain select * from test02 where a3 = '' order by a2; 都会出现filesort 执行 explain select * from test02 where a1 = '' order by a1; explain select * from test02 where a2 = '' order by a2; explain select * from test02 where a3 = '' order by a3; 则不会出现
小结:单索引情况下:查询和排序使用相同的索引不会出现filesort,查询和排序使用不同的索引会出现filesort。因为使用不同的索引列会重新进行一次排序。
创建表,创建复合索引 drop index idx_a1 on test02; drop index idx_a2 on test02; drop index idx_a3 on test02; 创建复合索引 alter table test02 add index idx_a1_a2_a3 (a1,a2,a3) ; 执行如下语句 explain select *from test02 where a1='' order by a3 ; --using filesort explain select *from test02 where a2='' order by a3 ; --using filesort explain select *from test02 where a1='' order by a2 ; explain select *from test02 where a2='' order by a1 ; --using filesort
小结:复合索引情况下:只要跨列或无序使用都会出现filesort