MySql数据库索引详解,索引看这一篇就够了

目录

1 为什么要使用索引?

2 索引的分类

3 索引的创建和删除

4 索引的执行过程

5 索引的底层实现原理

6 主键索引,辅助索引,聚集索引,非聚集索引

6.1 MyISAM存储引擎-主键索引

6.2 MyISAM存储引擎-辅助索引

6.3 InnoDB存储引擎-主键索引

6.4 InnoDB存储引擎-辅助索引

7 索引的相关问题

7.1 索引的设计原则

7.2 一次查询只能使用一个索引?

7.3 所有的查询语句都能用到索引吗?

 


推荐书籍《mysql索引漫画》,书籍链接如下:

链接:https://pan.baidu.com/s/1Vh4N_S0pPd9_sYN04cIUsw
提取码:b8or 

1 为什么要使用索引?

索引就像书籍的目录,当我们要查找要看的内容的时候,先从目录开始,找到内容对应的页数,再翻到相应的页去查看就可以了,这样通过目录去查找的方式比我们一页一页去查找效率高出很多,所以索引的核心就是加快SQL的查询。

如果表中的数据量非常大,那么一个SQL查询花费的时间是非常长的,那么此时应用索引来提升查询的效率就是非常有必要的。

同时由于索引也是需要存储成索引文件的,因此对索引的使用会涉及大量的磁盘I/O操作,如果索引创建过多,使用不当,那么在SQL查询的时候就会进行大量的磁盘I/O操作,这样反而降低了查询的效率。因此,对索引的执行过程和实现原理进行进一步的理解就显得特别重要。

2 索引的分类

首先,索引是创建在表中的字段上的,是对数据库表中的一列或者多列进行排序的结果。

按照索引字段可以将索引分为以下几类:

  1. 普通索引:没有任何限制条件,可以给任何类型的字段创建索引
  2. 唯一性索引:使用UNIQUE修饰的字段,值唯一,主键索引就是一种唯一性索引
  3. 主键索引:使用PRIMARY KEY修饰的字段,存储引擎会自动为其创建索引
  4. 单列索引:在一个字段上创建索引
  5. 多列索引:在多个字段上创建索引
  6. 全文索引:使用FULLTEXT参数可以设置全文索引,仅支持CHAR,VARCHAR和TEXT类型,只有MyISAM引擎支持

在数据库中,如果表中设立了主键,那么会有一个存储引擎自动创建的索引叫做主键索引,其他由我们自己常见的索引叫做辅助索引

3 索引的创建和删除

索引的创建有两种方式,一种是在创建表的时候指定索引字段,另一种是在已经创建的表上添加索引:

在创建表的时候指定索引:

CREATE TABLE index1(id INT,

                     name VARCHAR(20),

                     sex ENUM('male', 'female'),

                     INDEX(id));

上述为字段id添加了索引。

在已经创建的表上添加索引:

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX 索引名

         ON 表名 (属性名 [ASC | DESC]);

  • UNIQUE:可选。表示索引为唯一性索引。
  • FULLTEXT:可选。表示索引为全文索引。
  • SPATIAL:可选。表示索引为空间索引。
  • ASC:可选。表示升序排列。
  • DESC:可选。表示降序排列。

索引的删除非常简单,如下:

DROP INDEX 索引名 ON 表名;

4 索引的执行过程

首先我们创建一张表,格式如下(没有辅助索引):

然后向表中插入一些数据,如下:

如果我们要查看名字为liu的同学的成绩,那么sql语句的执行计划如下,用到关键explain

上图中rows为4表示一共查询了四行数据,就是将整个表都查询了一遍。那么如果这个表中有成千上万条数据,那么为了查询一条数据,就要搜索成千上万次,效率低下。

接下来我们为student表中的字段name添加索引,然后再来看sql语句的执行计划:

可以看到sql语句的执行计划里面rows为1,表明这次查询liu同学的信息,查询一次就查询到了。

5 索引的底层实现原理

MySQL支持两种索引,一种的B-树索引,一种是哈希索引,大家知道,B-树和哈希表在数据查询时的效率是非常高的。

这里我们主要讨论一下MySQL InnoDB存储引擎,基于B-树(但实际上MySQL采用的是B+树结构)的索引结构。B-树是一种m阶平衡树,叶子节点都在同一层,由于每一个节点存储的数据量比较大,索引整个树的层数是非常低的,基本上不超过三层。

由于磁盘的读取是按block块操作的(内存是按page页面操作的),因此B-树的节点大小一般设置为和磁盘块大小一致,这样一个B-树节点,就可以通过一次磁盘I/O把一个磁盘块的数据全部存储下来,所以当使用B-树存储索引的时候,磁盘I/O的操作次数是最少的(MySQL的读写效率,主要集中在磁盘I/O上)。

那么MySQL最终为什么要采用B+树存储索引结构呢,那么看看B-树和B+树在存储结构上有什么不同?

  1. B-树的每一个节点,存了关键字和对应的数据地址,而B+树的非叶子节点只存关键字,不存数据地址。因此B+树的每一个非叶子节点存储的关键字是远远多于B-树的,B+树的叶子节点存放关键字和数据,因此,从树的高度上来说,B+树的高度要小于B-树,使用的磁盘I/O次数少,因此查询会更快一些。
  2. B-树由于每个节点都存储关键字和数据地址,因此离根节点进的数据,查询的就快,离根节点远的数据,查询的就慢;B+树所有的数据都存在叶子节点上,因此B+树上搜索关键字,找到对应数据的时间是比较平均的,没有快慢之分。
  3. 在B-树上如果做区间查找,遍历的节点是非常多的;B+树所有叶子节点被连接成了有序链表结构,因此做整表遍历和区间查找是非常容易的。

哈希索引当然是由哈希表实现的,哈希表对数据并不排序,因此不适合做区间查找,效率非常低,需要搜索整个哈希表结构。

B-树的结构图如下:

 

B+树的结构图如下:

从上面的两个图,请验证前面给出的MySQL最终采用了B+树存储索引的结论。请仔细理解索引的底层实现原理(B+树),这个是面试经常会问到的问题!

6 主键索引,辅助索引,聚集索引,非聚集索引

我们主要学习一下MySQL两个重要的存储引擎,MyISAM和InnoDB存储引擎的索引结构。

6.1 MyISAM存储引擎-主键索引

MyISAM引擎使用B+树作为索引结构,叶节点的data域存放的是数据记录的地址。下图是MyISAM主键索引的原理图:

6.2 MyISAM存储引擎-辅助索引

在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复,如果给其它字段创建辅助索引,结构图如下:

根据上面两张图,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。

可以看到,MyISAM存储引擎,索引结构叶子节点存储关键字和数据地址,也就是说索引关键字和数据没有在一起存放,体现在磁盘上,就是索引在一个文件存储,数据在另一个文件存储,例如一个user表,会在磁盘上存储三个文件 user.frm(表结构文件) user.MYD(表的数据文件) user.MYI(表的索引文件)。

MyISAM的索引方式也叫做非聚集索引,之所以这么称呼是为了与InnoDB的聚集索引区分!

6.3 InnoDB存储引擎-主键索引

InnoDB存储引擎的主键索引,叶子节点中,索引关键字和数据是在一起存放的,如图:

可以看到,索引关键字和数据在叶节点上,在一起存储。

6.4 InnoDB存储引擎-辅助索引

InnoDB的辅助索引,叶子节点上存放的是索引关键字和对应的主键,如图:

辅助索引的B+树,先根据关键字找到对应的主键,再去主键索引树上找到对应的行记录数据。

从索引树上可以看到,InnoDB的索引关键字和数据都是在一起存放的,体现在磁盘存储上,例如创建一个user表,在磁盘上只存储两种文件,user.frm(存储表的结构),user.ibd(存储索引和数据)。

InnoDB的索引树叶节点包含了完整的数据记录,这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。

7 索引的相关问题

7.1 索引的设计原则

从前面的内容可以看到,索引固然很好,但是给表创建过多的索引,效率反而会降低,因此在给表设计索引的时候,需要遵循以下的设计原则:

1.给区分度高的字段创建索引

2.给经常需要排序,分组和多表联合操作的字段创建索引

3.给常作为查询条件的字段创建索引

4.索引的数目不宜过多

5.使用数据量少的索引(如前缀索引,主要针对字符串类型,字符串类型尽量创建前缀索引

6.对于多列索引,优先指定最左边的列集

7.删除不再使用或者很少使用的索引

8.尽量避免select *

7.2 一次查询只能使用一个索引?

一次查询只能使用一条索引,因为如果一个表上的索引过多的话,可能会影响MySql的判断,从而走不到正确索引,但是,如果你确实需要用到多条索引可以通过FORCE 关键字强制指定使用某个索引。

7.3 所有的查询语句都能用到索引吗?

并不是所有的查询语句都会用到索引的,以下几种查询语句有以下几种情况的时候是用不到索引的。

  • like通配符在最左
  • in 和not in
  • !=、<>
  • 对列做函数运算
  • 隐式数据类型转换
  • or子句

 

原创文章 162 获赞 95 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42214953/article/details/106006936