概述
前言
数据库索引是数据库的重要组成部分,无论在日常开发还是在数据库面试中都占有很重要,是后端开发人员在行业内生存的必备技能。下文我们就以下面这几个问题对数据库索引进行展开分析
- 为什么要使用索引
- 索引的数据结构
- 索引的类型
- 密集索引和稀疏索引
- 索引的优缺点
- 怎样创建合理的索引
问题分析
1.为什么要使用索引
这个就要讨论一下索引的作用了,索引的作用很容易理解。索引就是数据库数据的目录,在数据量很大情况下可以避免进行全表扫描查找数据,其实就是帮助我们更快速的定位到数据,说白了就是加快查找速度
2.索引的数据结构
这里就不长篇大论各种数据结构了,就列出几种常见的索引数据结构
- B-tree(B树)
- B+-tree(B+树)
- B*tree(B*树)
- Hash
MySQL数据库索引的数据结构就是B+树,对这些数据结构有兴趣的同学戳这里:https://zhuanlan.zhihu.com/p/27700617
3.索引的类型(MySQL)
- 主键索引:字段不能重复,不能有null,一张表只有一个主键索引
- 唯一键索引:字段不能重复,可以有null,一张表可以有多个唯一索引
- 普通索引:对字段没有特定要求,帮助提高查询速度
- 组合索引:多个字段组成索引,用于组合搜索
- 全文索引:对文本的内容进行分词,进行搜索(MyISAM才有)
4.密集索引和稀疏索引
先说密集索引和稀疏索引的区别吧
- 数据库表中数据的物理存储顺序和索引的顺序一样,因为物理存储顺序只有一种,所以一张表也只能有一个密集索引。索引树的叶子节点存储的就是行数据(索引树和数据是存储在一起的)
- 数据库表中数据的物理存储顺序和索引的顺序不一样,索引树的叶子节点存储的是指向数据的指针(数据和索引树分开存储)
InnoDB和MyISAM的索引
- MyISAM
-
MyISAM中不论是主键索引、还是任何其他键值索引都是稀疏索引,并且每个索引树之间没有联系。索引树叶子节点中存储的是指向数据的指针,对任何一个索引进行一次索引查找(不依赖于其他索引树)就能找到数据
如上图,不管是通过主键索引查找还是其他键索引查找,查找一颗索引树找到指向数据的指针后就能找到数据
- InnoDB
- InnoDB必须有且只有一个密集索引;数据表如果中定义了主键,则主键作为密集索引;数据表入如果没有定义主键则第一个唯一非空索引作为密集索引;如果两个条件都不满足,InnoDB内部会生成一个隐藏主键作为密集索引。当通过密集索引进行查找时,只需要一次索引查找就能就到数据
-
除了密集索引(一般情况是主键索引,上面说了)外的其他键索引都可以说是稀疏索引,但是这里的稀疏索引和MyISAM中的稀疏索引有些不同,不同在于哪里?
上文指出了MyISAM的稀疏索引“对任何一个索引树进行一次索引查找(不依赖于其他索引树)就能找到数据”,但是在InnoDB中根据稀疏索引查找数据时需要查找两颗索引树(二次查找),因为InnoDB中稀疏索引树中叶子节点存储的是密集索引的键值而不是指向数据的指针,下面图解
如上图,如果以主键作为密集索引。看绿色线条,当使用主键索引(密集索引)进行查找时,只需要对主键索引进行查找就能找到数据;看红色线条,当使用其他键创建的稀疏索引进行搜索时,第一步先从稀疏索引中查找到id值(主键值),第二步在密集索引中根据第一步找到的id值(主键值)找到数据,这就是常说的“二次查找”问题。也就是在InnoDB中不论通过哪个索引查找数据,一定会经过密集索引
- 总结InnoDB和MyISAM的索引区别
- InnoDB主键索引是密集索引,MyISAM主键索引是稀疏索引
- InnoDB其他键索引叶子节点存储密集索引的键值(一般是主键值),MyISAM其他键索引叶子节点存储指向数据存储位置的指针
- InnoDB数据和索引存储在一个文件,MyISAM数据和索引分开存储
5.索引的优缺点
优点
- 提高查找数据的效率,这也是创建索引的主要目的
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
- 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义
- 在使用分组和排序 子句进行数据检索时,同样可以显著减少查询中分组和排序的时间
- 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能
虽然索引的好处有这么多,但也不是创建越多越好,下面说一下索引的缺点
缺点
- 索引占用磁盘空间,索引越多占用磁盘空间越大
- 维护索引需要大量时间,并且随着数据量的增长而增长
- 对数据进行增删改时,由于索引也需要动态维护,增删改的效率会变低,索引越多,增删改的效率越低
6.怎样创建合理的索引
索引的优缺点我们都知道了,那要怎样创建索引才合理呢?
- 主键默认就是主键索引
- 数据量较大的表才考虑创建索引
- 有频繁的数据写入操作的表不要过多的索引
- 经常出现在where子句或者经常用于连接的字段最好创建索引
- 太长的文本字段不要创建索引