mysql优化在实际的开发中是很重要,有不少能够评估本身写的sql的质量与效率,mysql为咱们提供了一个辅助武器explain,它向咱们展现了mysql接收到一条sql语句的执行计划,根绝explain返回的结果能够知道sql写的怎样,mysql
建表语句sql
CREATE TABLE test (
id INT(11) NOT NULL AUTO_INCREMENT,
uname VARCHAR(255),
age int,
PRIMARY KEY (id)
);
alter table test add index uname_index(uname);
复制代码
表中数据以下数据库
id | uname | age |
---|---|---|
1 | lxh | 24 |
3 | zhangsan | 23 |
10 | sdsx | 12 |
11 | x33 | 35 |
explain的关键字有不少,此处只讲解最关键的type,key,rowsbash
类型,官方全程“join type”,意思是“链接类型”,注意这里不是字面意思量表之间的连接,确切说是数据库引擎查找表的一种方式,在《高性能mysql》一书中做者更是以为称呼它为访问类型更贴切一些;mysql优化
type的类型达到了14种之多,这里只记录和理解最重要且常常碰见的六种类型,它们分别是all,index,range,ref,eq_ref,const。从左到右,它们的效率依次是加强的oracle
全表扫描,若是只是查找一个数据项的sql出现了all类型,表明sql处于一种最原声的状态,有很大的优化空间,就比如一万我的中找一我的,只能挨个找一遍 以test表为例 函数
另外一种方式的全表扫描,只不过是按照索引的顺序, post
查找条件列使用了索引并且不为主键和unique,意思就是虽然使用了索引,但该索引列的值并不惟一,有重复 好比,test表的索引是 uname性能
ref_eq 与 ref相比牛的地方是,它知道这种类型的查找结果集只有一个,使用了主键或者惟一性索引进行查找时, 下面这两张表一张学生表,一张成绩表,成绩表里的学生id,t_id,就是使用了主键优化
-- 建表语句
create table ref_stu2 (
id INT(11) NOT NULL AUTO_INCREMENT,
uname VARCHAR(255),
age VARCHAR(255),
PRIMARY KEY (id)
);
create table ref_score2 (
id INT(11) NOT NULL AUTO_INCREMENT,
stu_id int(11) not null,
score int(11),
PRIMARY KEY (id)
);
explain select * from ref_stu2 stu, ref_score2 sc where stu.id = sc.stu_id;
复制代码
输出结果
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | stu | NULL | ALL | PRIMARY | NULL | NULL | NULL | 1 | 100 | NULL |
1 | SIMPLE | sc | NULL | eq_ref | uk_score_stuid | uk_score_stuid | 4 | lxhtest.stu.id | 1 | 100 | NULL |
将一个主键放置到where后面做为条件查询,mysql优化器就能把此次查询优化转化为一个常量
explain select * from ref_stu2 stu where stu.id = 1;
复制代码
执行结果以下
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | stu | null | const | PRIMARY | PRIMARY | 4 | const | 1 | 100 | null |
查询使用到的索引,type类型为index_merge(查询使用了两个以上的索引)时,这里可能出现两个以上的索引,其余的select_type这里只会出现一个。
这里是执行计划中估算的扫描行数,不是精确值,值越小,表明效率越高
覆盖索引(covering index)指一个查询语句的执行只用从索引中就可以取得,没必要从数据表中读取
总结:like关键字是否使用索引的前提是作前缀原则,即‘x’和‘x%’是使用索引的,他们的执行计划中type都是range,rows都是比表的行数少的,而其余两个type都是index,这种状况叫,全索引扫描,具体介绍以下, 若是模糊查询时,查询是否包含某个字符串,能够采用locate函数,select * from test where locate("x",uname);
查询test表中uname字段,含有字符串‘x’的数据。
full index scan:全索引扫描,查询时,遍历索引树来获取数据行。若是数据不是密集的会产生随机IO 在执行计划中是Type列,index
full table scan:经过读物理表获取数据,顺序读磁盘上的文件。这种状况会顺序读磁盘上的文件。 在执行计划中是Type列,all
covering index:覆盖索引,若是where条件的列和返回的数据在一个索引中,那么不须要回查表,那么就叫覆盖索引。 在执行计划中是extra那一列,using index
全索引扫描通常状况下比全表扫描好,但必定不是绝对的
大多数数据是存在磁盘上的,读取磁盘的次数是影响效率的关键。 因为索引扫描后要利用索引中的指针去逐一访问记录,假设每一个记录都使用索引访问,则读取磁盘的次数是查询包含的记录数T; 若是表扫描则读取磁盘的次数是存储记录的块数B; 若是T>B 的话索引就没有优点了,对于大多数数据库来讲,这个比例是10%(oracle,postgresql等),最终执行的时候,先对结果数量估算,若是小于(T<B)这个比例用索引,大于的话即直接表扫描因此结果也就不必定咯。
引用网上的一个例子 已知以下信息: 假设一张表含有10万行数据--------100000行 咱们要读取其中20%(2万)行数据----20000行 表中每行数据大小80字节----------80bytes 数据库中的数据块大小8K----------8000bytes 因此有如下结果: 每一个数据块包含100行数据---------100行(数据块大小/每行数据的大小 8000/80 ) 这张表一共有1000个数据块--------1000块(数据总条数/每一个块包含的数据个数 100000/100)
背后的故事:
经过索引读取20000行数据 = 约20000个table access by rowid = 须要处理20000个块来执行这个查询(经过索引去读数据,在索引中找到一个键值,而后这个键值对应的rowid去读表数据,rowid只对应一条记录,因此读一个块也只是为了找到对应rowid的那条记录,因此一次在一个块中只读一条记录) 而若是是全表扫描呢,这个表一共是1000块,也就1000次读取,采用后者明显效率高。
小计:最近在看mongo,发现原来mongo里也有这个关键字,哈哈,看来是通用的啊
参考连接: mysql中explain的type的解释 你的like语句为啥没索引
安利一个个人博客:Linnxh的博客