索引的好处
索引:提高数据库的性能,索引是物美价廉的东西了。不用加内存,不用改程序,不用调sql,只要执行正确的create index ,查询速度就可能提高成百上千倍。但是天下没有免费的午餐,查询速度的提高是以插入、更新、删除的速度为代价的,这些写操作,增加了大量的IO。所以它的价值,在于提高一个海量数据的检索速度。
查看有索引与没有索引的现象
首先我创建了一个表向表里面插入了800万条数据,我们想要查找一个人的时间如下:
当我们加了索引之后再查找的时间如下:
认识索引前的铺垫:磁盘IO
磁盘随机访问(Random Access)与连续访问(Sequential Access)
MySQL 与磁盘交互基本单位
建立共识
下面画图来说明MySQL如何工作的:(重要!!!!!)
为何MySQL的IO交互要是 Page
正式学习索引!
创建带有主键表查看效果
理解索引结构
理解单个Page
MySQL 中要管理很多数据表文件,而要管理好这些文件,就需要 先描述,在组织 ,我们目前可以简单理解成一个个独立文件是有一个或者多个Page构成的。
理解多个Page
通过上面的分析,我们知道,上面页模式中,只有一个功能,就是在查询某条数据的时候直接将一整页的数据加载到内存中,以减少硬盘IO次数,从而提高性能。但是,我们也可以看到,现在的页模式内部,实际上是采用了链表的结构,前一条数据指向后一条数据,本质上还是通过数据的逐条比较来取出特定的数据。
如果有1千万条数据,一定需要多个Page来保存1千万条数据,多个Page彼此使用双链表链接起来,而且每个Page内部的数据也是基于链表的。那么,查找特定一条记录,也一定是线性查找。这效率也太低了。
页目录(目录,是一种“空间换时间的做法”)
总结:有了目录可以帮我们很快的查找到当前Page中的信息,比如我找10,目录中有1,9,11那么我就可以直接总9开始找,跳过1~8大大提高查找效率就像看书的目录找目标页一样!!
单页情况
针对上面的单页Page,我们能否也引入目录呢?当然可以
多页情况
MySQL 中每一页的大小只有 16KB ,单个Page大小固定,所以随着数据量不断增大, 16KB 不可能存下所有的数据,
那么必定会有多个页来存储数据。
这样,我们就可以通过多个Page遍历,Page内部通过目录来快速定位数据。可是,貌似这样也有效率问题,在Page之间,
也是需要 MySQL 遍历的,遍历意味着依旧需要进行大量的IO,将下一个Page加载到内存,进行线性检测。
这样就显得我们之前的Page内部的目录,有点杯水车薪了
那么如何解决呢?解决方案,其实就是我们之前的思路,给Page也带上目录。
使用一个目录项来指向某一页,而这个目录项存放的就是将要指向的页中存放的最小数据的键值。
和页内目录不同的地方在于,这种目录管理的级别是页,而页内目录管理的级别是行。
其中,每个目录项的构成是:键值+指针。图中没有画全
存在一个目录页来管理页目录,目录页中的数据存放的就是指向的那一页中最小的数据。有数据,就可通过比较,找到该访问那个Page,进而通过指针,找到下一个Page。
真正的索引结构!!
其实目录页的本质也是页,普通页中存的数据是用户数据,而目录页中存的数据是普通页的地址。可是,我们每次检索数据的时候,该从哪里开始呢?虽然顶层的目录页少了,但是还要遍历啊?不用担心,可以在加目录页
这货就是传说中的B+树啊!没错,至此,我们已经给我们的表user构建完了主键索引。
随便找一个id=?我们发现,现在查找的Page数一定减少了,也就意味着IO次数减少了,那么效率也就提高了
整体了解索引结构的索引流程
InnoDB 在建立索引结构来管理数据的时候,其他数据结构为何不行?(因为我们希望索引结构是“矮胖”类型的!!)
B+ vs B与为什么选择B+
聚簇索引 VS 非聚簇索引
观察非聚簇索引
聚簇索引
普通索引
MySQL 除了默认会建立主键索引外,我们用户也有可能建立按照其他列信息建立的索引,一般这种索引可以叫做辅助(普通)索引。
MyISAM 的普通索引
对于 MyISAM ,建立辅助(普通)索引和主键索引没有差别,无非就是主键不能重复,而非主键可重复。
下图就是基于 MyISAM 的 Col2 建立的索引,和主键索引没有差别
InnoDB 的普通索引
同样,InnoDB 除了主键索引,用户也会建立辅助(普通)索引,我们以上表中的 Col3 建立对应的辅助索引如下图:
如果我建表的时候没设置主键那还能创建索引吗?
这个问题一开始我也很好奇,直到查完资料后豁然开朗!