MySQL - 索引及优化分析EXPLAIN

首先抛出个问题,什么会引起sql慢、性能下降?
答:执行时间长、等待时间长会导致sql慢,具体来说:
    1.查询语句写的烂
    2.索引失效,而索引又分为
    *单值索引:给表只给一个字段建立的索引;        create index idx_user_name on user(name);
    *复合索引:给表的多个字段联合在一起,建立的索引。        create index idx_user_nameEmail on user(name,email);
    3.关联查询join太多了
    4.服务器级别的参数调优

 

SQL执行顺序以及join
 
首先学习一下join的基本使用: https://blog.csdn.net/u012410733/article/details/63684663   这篇博客很有帮助

MySQL - 索引及优化分析EXPLAIN_第1张图片

(这是人读的顺序)
然后知道机读是先From 表名  ,Select 放在order by之前(即处在倒数第二位)

 


索引

存放在磁盘
索引是数据结构,一种排好序的、可以快速查找的数据结构。

MySQL使用InnoDB引擎时,支持的是B+树数据结构

使用索引的举例:
Col2是数据本身;
使用索引后,添加了Col1,Col1是指向数据本身的物理地址的指针。(即蓝色字说的“数据库还维护这一个满足特定查找算法的数据结构”)
以二叉树的形式存储这种带上了索引的新数据结构(真实情况是甚至是三叉数、四叉树等,这里二叉树只是举例,所以统称为B+树以后)

MySQL - 索引及优化分析EXPLAIN_第2张图片

MySQLInnoDB支持B+树索引、全文索引、自适应哈希索引

优点:
通过索引检索,提高查找效率(即降低数据库IO成本);(一个节点对应一次IO,将磁盘文件加载到内存)
通过索引排序,降低排序成本(即降低CPU消耗)。
缺点:
索引本身占空间,一般放硬盘而非内存;
索引查找快,但是增、改、删慢,因为更新表时,不光保存数据还保存索引文件每次更新添加了索引列的字段;

 

分类

单值索引:一个索引只能包含一个列,但一张表可以有多个单值索引;
复合索引:一个索引包含多个列
(聚集索引、辅助索引(次要索引)既可以是单值索引的形态,也可以是复合索引的形态)
MySQL中一定有主键索引(不指定的话会默认创建一个主键索引列),主键索引就是聚集索引

唯一索引:首先唯一索引是个索引,但是选列有讲究,必须是唯一的值,可以为NULL,但NULL只能有一个。(唯一索引可以用在单值索引上,也可以用在复合索引上)

 

使用

创建:

如:CREATE INDEX idx_t1_col1Col2 ON t1(col2,col2);


AlTER TABLE tableName ADD INDEX indexName ON (colName);

如:ALTER TABLE t1 ADD INDEX idx_t1_col1Col2 ON (col1,col2);

如果创建的是唯一索引,需要先给列设为主键:(错了吧,非主键列也可以作为唯一索引、一个表可以有多个唯一索引,主键一定是唯一索引,唯一索引不一定是主键)

主键不能为NULL(虽然主键列一定是可以为NULL的唯一索引列,这两者不矛盾)

MySQL - 索引及优化分析EXPLAIN_第3张图片

MySQL - 索引及优化分析EXPLAIN_第4张图片

MySQL - 索引及优化分析EXPLAIN_第5张图片

这是棵B+数;
浅蓝色是磁盘块,深蓝色是数据项(所对应数据并不真实存在于页中),黄色是指针;
(B+树无论是聚集索引还是辅助索引,其非叶子节点都有索引列。
对于聚集索引,叶子节点存放了索引列及其完整数据
对于辅助索引,叶子节点存放了索引列及其对应的主键)

真实数据都在叶子结点;(B树的真实数据分布在整个树中)
树高即是查找时的最大IO数(这里规定只有根节点的树树高为1);(这也是为什么不用二叉树的原因,为了减少IO)
IO时会把对应磁盘块内容从磁盘加载到内存;

B+树是B树的变体,为了提高查询效果:

* b+树的中间节点不保存数据,所以磁盘页能容纳更多节点元素,更“矮胖”;

* b+树查询必须查找到叶子节点,b树只要匹配到即可不用管元素位置,因此b+树查找更稳定(并不慢);

* 对于范围查找来说,b+树只需遍历叶子节点链表即可(因为B+树中的叶子结点通过链表是直接相连的),b树却需要重复地中序遍历

 


EXLAIN关键字

MySQL - 索引及优化分析EXPLAIN_第6张图片

建表sql:
CREATE TABLE `student` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `tel` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) CHARSET=utf8;

并设tel为普通索引:
CREATE INDEX idx_student_tel ON student(tel);

1.我自己验证举出了例子

explain select * from student where `name` = 'zz';

这是因为name列既不是主键也不是索引,因此只能采用全表扫描来查找目标name。(即type=all)

 

2.我自己验证举出了例子

索引做扫描,是基于索引在索引的叶子节点上找满足条件的数据
index类型,需要扫描索引上的全部数据。

explain SELECT count(*) FROM student;

 

3.我自己验证举出了例子

前提:查找在一定范围内的数据,这个查询条件必须是建立了索引的!否则就是个最垃圾的ALL。
指的是有范围的索引扫描,相对于index的全索引扫描,它有范围限制,因此要优于index。
除了显而易见的between,and以及'>','<'外,in和or也是索引范围扫描。

explain select * from student where tel<"123";

 

4.我自己验证举出了例子

前提:查找在一定范围内的数据,这个查询条件必须是建立了索引的!否则就是个最垃圾的ALL。
指的是有范围的索引扫描,相对于index的全索引扫描,它有范围限制,因此要优于index。
除了显而易见的between,and以及'>','<'外,in和or也是索引范围扫描。

explain select * from student where tel<"123";

 

4.我自己验证举出了例子

查找条件列使用了索引但是不为主键和unique。其实,意思就是虽然使用了索引,但该索引列的值并不唯一,有重复。这样即使使用索引快速查找到了第一条数据,仍然不能停止,要进行目标值附近的小范围扫描。但它的好处是它并不需要扫全表,因为索引是有序的,即便有重复值,也是在一个非常小的范围内扫描。
在employee表中根据tel查找数据的时候,mysql优化器便选择了ref的连接类型

mysql> explain select * from employee where `tel` = '123';

 

MySQL - 索引及优化分析EXPLAIN_第7张图片

 

6.我自己验证举出了例子

通常情况下,如果将一个主键放置到where后面作为条件查询,mysql优化器就能把这次查询优化转化为一个常量。
WHERE条件筛选后表上至多有一条元组匹配时,比如WHERE ID = 1 (ID是主键,值为1的要么有一条要么没有)

mysql> explain select * from employee where id = 1;

MySQL - 索引及优化分析EXPLAIN_第8张图片

MySQL - 索引及优化分析EXPLAIN_第9张图片

MySQL - 索引及优化分析EXPLAIN_第10张图片

 

自己总结:
1.感觉Using index就是用到了索引,就会出现,即不会在数据的基础上查找,而是在索引的基础上查找,good(这个就叫索引覆盖??NO!索引覆盖是指MySQL可以利用索引返回字段,而不必根据索引再次读取数据文件,换句话说查询列被所建立的索引覆盖了,好像在讲possible_keys+key的时候举的那个例就和索引覆盖有关?Yes!因为你建的是col1_col2索引,刚好你要查的就是col1、col2字段);

2.如果出现Using where,表明索引在where条件中用到了;
3.没有出现说明只是为了获取查询结果,而用来读取数据。

 


索引优化

MySQL - 索引及优化分析EXPLAIN_第11张图片

MySQL - 索引及优化分析EXPLAIN_第12张图片

 


索引失效了怎么办

MySQL - 索引及优化分析EXPLAIN_第13张图片

MySQL - 索引及优化分析EXPLAIN_第14张图片

MySQL - 索引及优化分析EXPLAIN_第15张图片

MySQL - 索引及优化分析EXPLAIN_第16张图片

MySQL - 索引及优化分析EXPLAIN_第17张图片

 

MySQL - 索引及优化分析EXPLAIN_第18张图片

 

MySQL - 索引及优化分析EXPLAIN_第19张图片

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(MySQL)