通俗点讲
1、‘页’和操做系统的关系
①为何要有内存管理?
咱们知道,一个进程完成他的功能,须要访问磁盘加载数据到内存而后等待进入cpu运算,由于数据量大小远远大于内存大小。所以提出虚拟内存概念。虚拟内存就是将程序用到的数据进行划分,暂时用不到的放到磁盘里,用到的放到内存里,操做系统中老是运行着不止一个进程,各个进程有优先级顺序,因此存在进程调度问题,进程的每次调度都会致使内存和磁盘数据置换,段式内存管理页式内存管理都是基于虚拟内存概念的具体内存管理解决方案。html
②什么是页式内存管理?
虚拟内存位于程序和物理内存之间,程序只能看见虚拟内存,不再能直接访问物理内存。每一个程序都有本身独立的进程地址空间,这样就作到了进程隔离。这里的进程地址空间是指虚拟地址。顾名思义,既然是虚拟地址,也就是虚的,不是现实存在的地址空间。既然咱们在程序和物理地址空间之间增长了虚拟地址,那么就要解决怎么从虚拟地址映射到物理地址,由于程序最终确定是运行在物理内存中的,主要有分段和分页两种技术。node
分页机制就是把内存地址空间分为若干个很小的固定大小的页,每一页的大小由内存决定,就像Linux中ext文件系统将磁盘分红若干个Block同样,这样作是分别是为了提升内存和磁盘的利用率。mysql
③页的大小为何是4K?
CPU位数准确地说应该是CPU一次可以并行处理的数据宽度,通常就是指数据总线宽度。(后续补充:参考http://blog.sina.com.cn/s/blo...
④mysql索引和页的关系
B-tree,B是balance,通常用于数据库的索引。使用B-tree结构能够显著减小定位记录时所经历的中间过程,从而加快存取速度。而B+tree是B-tree的一个变种,MySQL就广泛使用B+tree实现其索引结构。
通常来讲,索引自己也很大,不可能所有存储在内存中,所以索引每每以索引文件的形式存储的磁盘上。这样的话,索引查找过程当中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,因此评价一个数据结构做为索引的优劣最重要的指标就是在查找过程当中磁盘I/O操做次数的渐进复杂度。换句话说,索引的结构组织要尽可能减小查找过程当中磁盘I/O的存取次数。
为了达到这个目的,磁盘按需读取,要求每次都会预读的长度通常为页的整数倍。并且数据库系统将一个节点的大小设为等于一个页,这样每一个节点只须要一次I/O就能够彻底载入。每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。并把B-tree中的m值设的很是大,就会让树的高度下降,有利于一次彻底载入。web
2、聚簇索引和非聚簇索引
①mysql索引
B+Tree结构均可以用在MyISAM和InnoDB上。mysql中,不一样的存储引擎对索引的实现方式不一样,大体说下MyISAM和InnoDB两种存储引擎。算法
MyISAM的是非聚簇索引,B+Tree的叶子节点上的data,并非数据自己,而是数据存放的地址。主索引和辅助索引没啥区别,只是主索引中的key必定得是惟一的。这里的索引都是非聚簇索引。非聚簇索引的两棵B+树看上去没什么不一样,节点的结构彻底一致只是存储的内容不一样而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,
这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来讲,这两个键没有任何差异。因为索引树是独立的,经过辅助键检索无需访问主键的索引树。InnoDB的数据文件自己就是索引文件,B+Tree的叶子节点上的data就是数据自己,key为主键,这是聚簇索引。聚簇索引,叶子节点上的data是主键(因此聚簇索引的key,不能过长)。sql
InnoDB使用的是聚簇索引(有且只能有必须有一个)+非聚簇索引(其余索引,无关紧要),将主键(默认是聚簇索引)组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where id = 14"这样的条件查找主键,则按照B+树的检索算法便可查找到对应的叶节点,以后得到行数据。若对Name列进行条件搜索,则须要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操做,最终到达叶子节点便可获取整行数据。数据库
B+Tree示意图缓存
汇集索引和非汇集索引原理图数据结构
②聚簇索引(数据存储的顺序和聚簇索引存储的顺序一致,如新华字典中经过拼音查找)
聚簇索引的数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据必定也是相邻地存放在磁盘上的。聚簇索引要比非聚簇索引查询效率高不少。
汇集索引这种主+辅索引的好处是,当发生数据行移动或者页分裂时,辅助索引树不须要更新,由于辅助索引树存储的是主索引的主键关键字,而不是数据具体的物理地址。
③非聚簇索引(数据存储的顺序和聚簇索引存储的顺序一致,如新华字典中经过笔画查找,)
非汇集索引,相似于图书的附录,那个专业术语出如今哪一个章节,这些专业术语是有顺序的,可是出现的位置是没有顺序的。每一个表只能有一个聚簇索引,由于一个表中的记录只能以一种物理顺序存放。可是,一个表能够有不止一个非聚簇索引。性能
3、Page结构
Page是整个InnoDB存储的最基本构件,也是InnoDB磁盘管理的最小单位,与数据库相关的全部内容都存储在这种Page结构里。Page分为几种类型,常见的页类型有数据页(B-tree Node)Undo页(Undo Log Page)系统页(System Page) 事务数据页(Transaction System Page)等。单个Page的大小是16K(编译宏UNIV_PAGE_SIZE控制),每一个Page使用一个32位的int值来惟一标识,这也正好对应InnoDB最大64TB的存储容量(16Kib * 2^32 = 64Tib)。
澄清一个概念:innodb中,在聚簇索引之上建立的索引称之为辅助索引,辅助索引访问数据老是须要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、惟一索引,辅助索引叶子节点存储的再也不是行的物理位置,而是主键值
cluster.png
因为聚簇索引是将数据跟索引结构放到一块,所以一个表仅有一个聚簇索引
聚簇索引默认是主键,若是表中没有定义主键,InnoDB 会选择一个惟一的非空索引代替。若是没有这样的索引,InnoDB 会隐式定义一个主键来做为聚簇索引。InnoDB 只汇集在同一个页面中的记录。包含相邻健值的页面可能相距甚远。若是你已经设置了主键为聚簇索引,必须先删除主键,而后添加咱们想要的聚簇索引,最后恢复设置主键便可。
此时其余索引只能被定义为非聚簇索引。这个是最大的误区。有的主键仍是无心义的自动增量字段,那样的话Clustered index对效率的帮助,彻底被浪费了。
刚才说到了,聚簇索引性能最好并且具备惟一性,因此很是珍贵,必须慎重设置。通常要根据这个表最经常使用的SQL查询方式来进行选择,某个字段做为聚簇索引,或组合聚簇索引,这个要看实际状况。
记住咱们的最终目的就是在相同结果集状况下,尽量减小逻辑IO。
image
image
MyISM使用的是非聚簇索引,非聚簇索引的两棵B+树看上去没什么不一样,节点的结构彻底一致只是存储的内容不一样而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来讲,这两个键没有任何差异。因为索引树是独立的,经过辅助键检索无需访问主键的索引树。
看上去聚簇索引的效率明显要低于非聚簇索引,由于每次使用辅助索引检索都要通过两次B+树查找,这不是画蛇添足吗?聚簇索引的优点在哪?
image
因此建议使用int的auto_increment做为主键
image
主键的值是顺序的,因此 InnoDB 把每一条记录都存储在上一条记录的后面。当达到页的最大填充因子时(InnoDB 默认的最大填充因子是页大小的 15/16,留出部分空间用于之后修改),下一条记录就会写入新的页中。一旦数据按照这种顺序的方式加载,主键页就会近似于被顺序的记录填满(二级索引页多是不同的)
聚簇索引的数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据必定也是相邻地存放在磁盘上的。聚簇索引的顺序和磁盘中数据的存储顺序是一致的,若是主键不是自增id,那么能够想 象,它会干些什么,不断地调整数据的物理地址、分页,固然也有其余一些措施来减小这些操做,但却没法完全避免。但,若是是自增的,那就简单了,它只须要一 页一页地写,索引结构相对紧凑,磁盘碎片少,效率也高。
由于MyISAM的主索引并不是聚簇索引,那么他的数据的物理地址必然是凌乱的,拿到这些物理地址,按照合适的算法进行I/O读取,因而开始不停的寻道不停的旋转。聚簇索引则只需一次I/O。(强烈的对比)
不过,若是涉及到大数据量的排序、全表扫描、count之类的操做的话,仍是MyISAM占优点些,由于索引所占空间小,这些操做是须要在内存中完成的。
聚簇索引默认是主键,若是表中没有定义主键,InnoDB 会选择一个惟一的非空索引代替。若是没有这样的索引,InnoDB 会隐式定义一个主键来做为聚簇索引。InnoDB 只汇集在同一个页面中的记录。包含相邻健值的页面可能相距甚远。