1.索引的概念
索引:提高数据库的性能,索引是物美价廉的东西了。不用加内存,不用改程序,不用调sql,只要执行正确的 create index ,查询速度就可能提高成百上千倍。但是天下没有免费的午餐,查询速度的提高是以插入、更新、删除的速度为代价的,这些写操作,增加了大量的IO。所以它的价值,在于提高一个海量数据的检索速度。

当然索引也不例外;而索引之所以可以提高效率,本质上是改变了组织数据的方式;而我们的mysqld其实就是我们的进程,而索引其实就是进程中的一种数据结构;
2.索引的分类

3.见一见索引
先整一个海量表,在查询的时候,看看没有索引时有什么问题?
这个数据库的表里面有800万条我们生成的随机数;

现在我们来用以前的方法查一下具体的empno看看是否能查到;

我们查了几次发现几乎在5sec附近,这样的效率很低,因此我们就需要加索引了;

现在我们再去查找就发现时间变得非常快了;

4.索引的本质(就是B+的数据结构)
4.1mysql的存储
MySQL 给用户提供存储服务,而存储的都是数据,数据在磁盘这个外设当中。磁盘是计算机中的一个机械设备,相比于计算机其他电子元件,磁盘效率是比较低的,在加上IO本身的特征,可以知道,如何提交效率,是 MySQL 的一个重要话题。
4.2mysql中数据访问的理解
数据库文件,本质其实就是保存在磁盘的盘片当中,就是一个一个的文件;所以,最基本的,找到一个文件的全部,本质上就是在磁盘找到所有保存文件的扇区。而我们能够定位任何一个扇区,那么便能找到所有扇区,因为查找方式是一样的。

柱面==盘面(因为一个一个的盘累积起来成为了柱)

盘片在转动,磁头在左右摆动;
柱面==磁道

4.2.1定位扇区
++"定位一个文件的过程为;磁头->磁道->扇区(CHS)++
4.2.2 系统定位
不过实际系统软件使用的并不是 CHS (但是硬件是),而是 LBA ,一种线性地址,可以想象成虚拟地址与物理地址。系统将 LBA 地址最后会转化成为 CHS ,交给磁盘去进行数据读取。
4.3 数据库文件如何进行IO交互
在硬件层面定位任何一个基本数据块其实就是定位扇区。那么在系统软件上,就直接按照扇区(512字节,部分4096字节),进行IO交互吗?不是
如果操作系统直接使用硬件提供的数据大小进行交互,那么系统的IO代码,就和硬件强相关,换言之,如果硬件发生变化,系统必须跟着变化;从目前来看,单次IO 512字节,还是太小了。IO单位小,意味着读取同样的数据内容,需要进行多次磁盘访问,会带来效率的降低。
之前学习文件系统,就是在磁盘的基本结构下建立的,文件系统读取基本单位,就不是扇区,而是数据块。所以系统读取磁盘,是以块为单位的,基本单位是 4KB。
4.4 磁盘随机访问与连续访问
随机访问:本次IO所给出的扇区地址和上次IO给出扇区地址不连续,这样的话磁头在两次IO操作之间需要作比较大的移动动作才能重新开始读/写数据。
连续访问:如果当次IO给出的扇区地址与上次IO结束的扇区地址是连续的,那磁头就能很快的开始这次IO操作,这样的多个IO操作称为连续访问。
因此尽管相邻的两次IO操作在同一时刻发出,但如果它们的请求的扇区地址相差很大的话也只能称为随机访问,而非连续访问。磁盘是通过机械运动进行寻址的,连续访问不需要过多的定位,故效率比较高。
4.5 MySQL 与磁盘交互基本单位
而 MySQL 作为一款应用软件,可以想象成一种特殊的文件系统。它有着更高的IO场景,所以,为了提高基本的IO效率,**MySQL 进行IO的基本单位是 16KB ;**也就是说,磁盘这个硬件设备的基本单位是 512 字节,而 MySQL InnoDB引擎 使用 16KB 进行IO交互。

所以 MySQL 和磁盘进行数据交互的基本单位是 16KB 。这个基本数据单元,在 MySQL 这里叫做page;

4.6 Buffer Pool
MySQL 中的数据文件,是以page为单位保存在磁盘当中的。
MySQL 的 CURD 操作,都需要通过计算,找到对应的插入位置,或者找到对应要修改或者查询数据。
而只要涉及计算,就需要CPU参与,而为了便于CPU参与,一定要能够先将数据移动到存当中。 所以在特定时间内,数据一定是磁盘中有,内存中也有。后续操作完内存数据之后,以定的刷新策略,刷新到磁盘。而这时,就涉及到磁盘和内存的数据交互,也就是IO了。而此时IO基本单位就是Page。
为了更好的进行上面的操作, MySQL 服务器在内存中运行的时候,在服务器内部,就申请了被称为 Buffer Pool 的的大内存空间,来进行各种缓存 。其实就是很大的内存间来和磁盘数据进行IO交互。为了更高的效率,一定要尽可能的减少系统和磁盘IO的次数;
5.索引的底层
5.1测试
首先插入多条数据

查看插入结果

我们发现竟然默认是有序的!是谁干的呢?排序有什么好处呢?
为什么数据库在插入数据时要对其进行排序呢?我们按正常顺序插入数据不是也挺好的吗?
插入数据时排序的目的,就是优化查询的效率。页内部存放数据的模块,实质上也是一个链表的结构,链表的特点也就是增删快,查询修改慢,
所以优化查询的效率是必须的。正是因为有序,在查找的时候,从头到后都是有效查找,没有任何一个查找是浪费的,而且,如果运气好,是可以提前结束查找过程的;嘿嘿,读到后面你就会发现其实是为了引入页目录;
5.2 为何IO交互为Page
用多少,加载多少不好吗?
如果MySQL要查找id=2的记录,第一次加载id=1,第二次加载id=2,一次一条记录,那么就需要2次IO。如果要找id=5,那么就需要5次IO。
但是如果这5条(或者更多)都被保存在一个Page中(16KB,能保存很多记录),那么第一次IO查找id=2的时候,整个Page会被加载到MySQL的Buffer Pool中,这里完成了一次IO。但是往后如果在查找id=1,3,4,5等,完全不需要进行IO了,而是直接在内存中进行了。所以,就在单Page里面,大大减少了IO的次数。你怎么保证,用户一定下次找的数据,就在这个Page里面?我们不能严格保证,但是有很大概率,因为有
局部性原理:一次加载的数据,下一次很有可能在上次数据的附近,即为局部性原理。
往往IO效率低下的最主要矛盾不是IO单次数据量的大小,而是IO的次数。
5.3 理解单个page
理解单个PageMySQL 中要管理很多数据文件,而要管理好这些文件,就需要 先描述,在组织 ,我们目前可以简单理解成一个个独立文件是有一个或者多个Page构成的。
不同的 Page ,在 MySQL 中,都是 16KB ,使用 prev 和 next 构成双向链表;因为有主键的问题, MySQL 会默认按照主键给我们的数据进行排序,从上面的Page内数据记录可以看出,数据是有序且彼此关联的
5.4 理解多个page
通过上面的分析可知,页模式的核心思想是:在查询某条数据时,将一整页数据加载到内存,以减少硬盘I/O次数,从而提升性能。然而,页模式内部实际上仍采用链表结构------数据之间通过指针逐条链接,本质上还是在做逐条比较查找。
试想,如果有1000万条数据,势必分布在多个页中,页之间通过双链表连接,每个页内部也是链表结构。那么,要查找某条特定记录,依然需要线性遍历。这样的效率,显然太低了。

5.4.1页目录(又叫页内目录)
比如我们在阅读一本书的时候,需要查看具体的某一个章节,我们最高效的方法是查询目录,而我们的数据库也采用了这样的方法,***因此在单page中数据过多时引入了多page的概念,而更多page的时候引入的目录的概念;***那么当前,在一个Page内部,我们引入了目录。
比如,我们要查找id=4记录,之前必须线性遍历4次,才能拿到结果。++现在直接通过目录项2[3],直接进行定位新的起始位置,提高了效率++。在单表数据不断被插入的情况下, MySQL 会在容量不足的时候,自动开辟新的Page来保存新的数据,然后通过指针的方式,将所有的Page组织起来。使用一个目录项来指向某一页,而这个目录项存放的就是将要指向的页中存放的最小数据的键值 。
"空间换时间" 
5.4.2 页目录和页内目录的区别
和页内目录不同的地方在于,这种目录管理的级别是页,而页内目录管理的级别是行。
其中,每个
目录项的构成是:键值+指针。
5.5 目录页很多情况
其实目录页的本质也是页,普通页中存的数据是用户数据,而目录页中存的数据是普通页的地址。可是,我们每次检索数据的时候,该从哪里开始呢?虽然顶层的目录页少了,但是还要遍历啊?不用担心,可以再加目录页;

我们发现这就是传说中的B+树啊!没错,至此,我们已经给我们的表user构建完了主键索引。随便找一个id=?我们发现,现在查找的Page数一定减少了,淘汰率变高了,也就意味着IO次数减少了,那么效率也就提高了。

(B+树结构)
5.4 索引查找的本质总结
①Page分为目录页和数据页。目录页只放各个下级Page的最小键值。
②查找的时候,自定向下找,只需要加载部分目录页到内存,即可完成算法的整个查找过程,大大减少了IO次数;

非叶子结点不存数据,则可以存储更多的目录项,也就可以管理更多的page,这样这棵树一定是矮胖的,所以途径的变短,所以IO次数减少,也就提高了效率;所以这棵树就叫做innode db索引结构,所以我们mysql的增删查改就是在这棵树上进行的;
这棵树是被构建在哪里的呢?
答案是在我们mysql的buffer Pool中,一个表一个B+树;
6.其他的数据结构为什么不可以
很多树都会最糟糕的时候都会退化成线性结构,而B树中会在路上的结点也存储数据,而彼此的叶子结点没有链式相连;
7.聚簇索引 VS 非聚簇索引
7.1MyISAM的相关特点
**MyISAM 存储引擎-主键索引 ;**MyISAM 引擎同样使用B+树作为索引结果,叶节点的data域存放的是数据记录的地址。下图为 MyISAM表的主索引, Col1 为主键;

MyISAM的存储特点:

7.3MyISAM 和 InnoDB的区别

InnoDB 的非主键索引中叶子节点并没有数据,而只有对应记录的key(主键)值。
所以通过辅助(普通)索引,找到目标记录,需要两遍索引:首先检索辅助索引获得主键,然后
主键到主索引中检索获得记录。这种过程,就叫做回表查询;为何 InnoDB 针对这种辅助(普通)索引的场景,不给叶子节点也附上数据呢?原因就是太浪费空间
7.4 在mysql中看inno db 和 myisam的区别:
① innodb
首先先在mysql中建一张表,搜索引擎使用innoDB ;

然后再linux中看对应的信息

② myisam


7.5 myisam和innodb在实际开发的选择

MyISAM 是老古董,除非你是维护老系统或者有特殊需求(比如纯日志),否则不用考虑它。
