MySQL数据库索引知识小结

目录

一、为什么需要使用索引?

二、什么样的数据结构适合做索引?

2.1、Hash算法(index = hash(key)

         2.2、平衡二叉树

2.3、B树

2.4、B+树

三、B+树中的节点到底存放多少元素

四、密集索引和稀疏索引区别

五、Innodb与Myisam的索引区别

 5.1Innodb中采用的是聚簇索引+辅助索引

 5.2MyISM使用的是稀疏索引

六、索引在什么情况下会失效?

七、联合索引


一、为什么需要使用索引?

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构

白话文:索引就像书的目录一样可以非常快速的定位到书的页码

没有使用索引的后果:如果向mysql发出一条sql语句请求,查询的字段没有被创建索引的话,可能会导致全表扫描(数据库服务器用来搜寻表的每一条记录的过程,直到所有符合给定条件的记录返回为止),这样的话查询效率非常低

举例:如下图,此时数据库user表没有对user_id创建索引,这时执行下图中的select语句就会从第一行数据进行判断,直至判断到第七行的user_id=7找到了才会停止,这就是全表扫描,可以看到如果没有索引的话查询效率很低

MySQL数据库索引知识小结_第1张图片

到这里我们知道了索引的重要性,接下来就分析一下几种主流实现索引的数据结构,当然最重要的还是B+树

二、什么样的数据结构适合做索引?

首先我们看一下MySQL查询操作的流程:mysql的数据是存储在磁盘中的,因此当查找数据时需要:磁盘--->内存--->CPU

2.1、Hash算法(index = hash(key)

       是根据key、value形式而直接进行访问的数据结构。也就是说,它通过把key、value映射到表中的一个位置来访问记录,以加快查找的速度。

       比如我们如果使用Hash算法对下图中的user_name字段进行hash运算得到index

MySQL数据库索引知识小结_第2张图片

       这时如果执行了下面的这条sql语句,在查询时就会先通过index = hash(name)去得到index,然后直接去数组中根据index直接取得相应的数据,这样相比于全表扫描的效率大很多。(这里就不具体介绍散列冲突等情况了,我们的重点是B树)

 select * from  user where user_name='余胜军';

       优点: 通过字段的值计算hash值,定位数据非常快,查找速度快。

       缺点:不能进行范围查找,因为不能通过hash值去比较大小,因为index是经过hash计算的是散列的,这样就导致存储的数据没有顺序。

2.2、平衡二叉树

        这里简单介绍一下,平衡二叉树AVL除了具备二叉搜索树的基本特征外.,还具有一个非常重要的特点,任意节点的左子树和右子树高度差不能大于1(如果想要深入学习可以去看这篇文章平衡二叉树AVL)

       平衡二叉树查询原理:首先从根节点开始比较,若刚好等于根节点则直接返回,大于根节点就再去跟其右孩子比较,小于根节点就再和其左孩子比较,后续步骤依次推类.

        由于平衡查找树的查找时间复杂度是logn,因此就比没有什么最初没有索引进行的全表查找快很多,但是相对于hash算法直接定位比起来就差多了。并且二分搜索树的插入删除需要保证节点平衡性,这样就会导致插入、删除操作效率低。

        平衡二叉树支持范围查找,比如下图,我们要查找的值是小于5的数据,那么直接从根节点向下12->-8->5,然后将值为5节点的左子树全部返回即可。但是如果我们查询的是大于6的数据,则就会12->8->5,查找到5后然后再去向上回溯这就会导致AVL树的范围查找效率比较低。

MySQL数据库索引知识小结_第3张图片

 

        对于平衡二叉树作为索引的数据库而言,由于mysql查询时需要磁盘->内存->cpu,这时查找就会先将根节点数据取出来和待查找数据进行大小比较,如果不想等就要去磁盘中再去拿右孩子或者左孩子,着就会发生很多次的磁盘IO,这样就会造成性能的影响。

       优点:支持范围查询,查找时间复杂度是logn大于无索引情况,但是小于hash算法。

       缺点:插入和删除效率低,范围查找可能需要回溯,查询可能会有大量的磁盘IO。

2.3、B树

       由于AVL树进行查询时需要进行多次IO,其实本质上就是因为树的高度影响着IO次数,因此B树就出现了,B树首先就是减少了AVL树的高度。

       此时有值为1-10这10条数据分别存在AVL、B树中,通过下图来对比一下这两种数据结构区别。       

MySQL数据库索引知识小结_第4张图片

       上图中B树的m的意思是,这颗B树最多能含有几个孩子节点,可以发现在插入相同数据的情况下,B树比AVL树低,如果m选的更大那么会更低,在实际应用中m的大小会根据实际情况来定,总而言之B树比AVL树低!

        既然B树比AVL树低,那么在B树中进行查询操作的IO操作就会优于AVL树,但是B树对于范围查找仍然需要回溯节点

       优点:支持范围查询,查找时间复杂度会优于AVL树(减少了IO),但是小于hash算法。

       缺点:插入和删除效率低,范围查找可能需要回溯。

2.4、B+树

接下来就到了对于索引而言最重要的数据结构了,通过了前面几个数据结构的分析或多或少都有着一些问题。

  • Hash算法由于不能范围查询所以抛弃
  • AVL相对于Hash算法尽管查询性能低,但是可以范围查找,所以在没有B树的情况下索引大多使用AVL
  • B树查询性能高于AVL且也可以范围查找,因此选择B树

但是现如今Mysql的索引是通过B+树实现的,这时为什么呢?来看下图。

MySQL数据库索引知识小结_第5张图片

通过上图的对比可以发现,B+树在叶子节点冗余了所有非叶子节点的key,每个叶子节点增加了一个指向相邻叶子节点的指针,每个叶子节点也是最多容纳m-1个元素。

这样做的好处就是,在范围查询时不需要再进行回溯了,直接通过简单的链表操作即可。还需要注意B+树中的非叶子节点仅仅存储了key就是子树的最大最小值,只有叶子节点才存储了key和value,value就是真实的数据。

三、B+树中的节点到底存放多少元素

在之前举的例子中B+树的m为3,也就是一个节点最多有两个元素,最多有三个孩子。那么在实际应用中B+树对于m的取值是如何判断的呢?

计算机科学中有一个著名的局部原理:当一个数据被用到时,其附近的数据也通常会马上用到。

因此每次读取磁盘数据时其实不是严格的按需读取,而是每次都会预读,即使只需要读取磁盘的一个字节,磁盘也会从读取的这个位置开始读取“一定的数据”返回到内存中。

比如操作系统规定了每次读取磁盘数据都会返回4kb,此时如果进行磁盘读取了1bit数据也会从该数据的位置向后继续读取数据直到达到4kb返回到内存中。因此在实际应用中就需要根据操作系统规定来判断B+树的节点到底存放多少元素。

  • B+树的节点存放多少个元素应该是操作系统规定一次磁盘IO读取数据大小的整数倍
  • 因为小于和大于都会形成浪费,比如操作系统规定一次读取数据返回4kb到内存,这时如果B+树的节点的容量是3kb<4kb就会造成浪费,B+树的容量是5kb>4kb的话就又会返回8kb.

四、密集索引和稀疏索引区别

  • 聚簇索引:将数据存储与索引存储到了一块,找到索引也就找到了数据由于聚簇索引是将数据跟索引结构放到一块,因此一 个表仅有一个聚簇索引
  • 稀疏索引:将数据存储与索引分开存储,索引结构的叶子节点指向了数据的对应行,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因

五、Innodb与Myisam的索引区别

5.1Innodb中采用的是聚簇索引+辅助索引

  • innodb中,在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是数据行的物理位置,而是主键值
  • 聚簇索引默认是主键,如果表中没有定义主键,InnoDB 会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB 会隐式定义一个主键来作为聚簇索引。

此时,有一个user表,表中有3个字段分别是id、name、company,我们把id字段设为主键,那么id字段的索引也就成了聚簇索引,再把name字段设为唯一索引,那么name字段就是一个辅助索引,此时我们执行下面的sql语句

select * from user where id = 7;

对应着下图,当执行id = 7的sql语句时,由于id字段对应的是聚簇索引,那么会根据B+树算法找到对应的叶子节点,该叶子节点就存储了相应的id=7的数据行。

如果执行的是select * from user where name = 'Bezos'; 这时由于查询的name字段是一个辅助索引,那么就会先在辅助索引中根据name找到索引的具体位置,这个位置中存储的是主键值,也就是7,然后再通过主键索引进行查询7获取数据,这就是使用辅助索引为什么需要二次查找的原因。

MySQL数据库索引知识小结_第6张图片

 5.2MyISM使用的是稀疏索引

稀疏索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

MySQL数据库索引知识小结_第7张图片

六、索引在什么情况下会失效?

  • 如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)
  • 要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
  • 对于多列索引,不是使用的第一部分,则不会使用索引
  • .like查询以%开头
  • 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
  • 如果mysql估计使用全表扫描要比使用索引快,则不使用索引

七、联合索引

首先需要知道联合索引是什么,它就是索引由多个字段组成。比如下面的sql语句就是创建了一个由id、user_name字段组成的联合索引,并且插入了一条数据。

CREATE TABLE user_details (
  id int(11) DEFAULT NULL,
  user_name varchar(50) DEFAULT NULL,
  user_phone varchar(11) DEFAULT NULL,
  PRIMARY KEY (id,user_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO user_details VALUES(1,'xyz','111');

然后我们进行查询,.执行下面的sql语句,很显然使用到了索引,这还无疑问。

MySQL数据库索引知识小结_第8张图片

 然后再分别进行下面的查询语句。

MySQL数据库索引知识小结_第9张图片

 

MySQL数据库索引知识小结_第10张图片

 MySQL数据库索引知识小结_第11张图片

通过分析对比可以发现,只有执行SELECT * FROM user_details WHERE  user_name='xyz';语句时没有使用到索引,这就是因为联合索引的左前缀原则。

左前缀原则:在mysql建立联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配(不需要按照顺序来写,比如对于(a,b)联合索引写成 a and b 和 b and a都可以使用上索引)

你可能感兴趣的:(数据库)