聚簇索引:将数据与索引存放到一起,索引结构的叶子结点保存了行数据(索引临近的记录在物理存储上也是临近的)
非聚簇索引:数据与索引是分开存储的,索引结构的叶子结点指向了数据对应的位置(索引中临近的数据在物理存储上不一定临近)
主索引:每一块存储块有一个索引项,索引项总数和存储表存储块数目相同,存储表的每一存储块的第一条记录称为锚记录。
主索引的索引字段值为锚的索引字段值,指针指向其所在的存储块(按照索引字段排序,通常建立在排序的主码上)(一个主文件只能由一个主索引)
辅助索引:定义在主文件的任一或多个非排序字段上的辅助存储结构
辅助索引通常是对某一排序字段上的每一个不同值有一个索引项,索引字段即是该字段额不同值,而指针指向包含该记录的块(或是该记录本身)
(但是可以有多个辅助索引)
这里的排序字段值得就是聚簇索引,记录在物理块上的存储顺序就按照聚簇索引的字段排序
在innodb中,在聚簇索引之上创建的索引称之为辅助索引,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引等。
辅助索引叶子节点存储的不再是行的物理位置,而是主键的值,辅助索引访问数据总是需要二次查找
1.InnoDB使用的是聚簇索引,将主键组织到一颗B+树种,而行数据就存储在叶子结点上,若使用“where id =14”这样的条件查找主键,则按照B+树的检索算法即可查找到对应的叶子节点,之后获得行数据。
2.若对Name列进行条件搜索,则需要两个步骤:第一步在辅助索引B+树种检索Name,到达叶结点获取对应的主键。第二步使用主键在主索引B+树中在执行依次B+树检索操作,最终到达叶子结点即可获取整行数据。(重点在于通过其他键需要建立辅助索引。)
聚簇索引具有唯一性,由于聚簇索引是将数据和索引结构放在一起,因此一个表仅有一个聚簇索引。
表中行的物理顺序和索引中行的物理顺序是相同的,在创建任何非聚簇索引之前创建聚簇索引,这是因为聚簇索引改变了表中行的物理顺序,数据行 按照一定的顺序排列,并且自动维护这个顺序;
聚簇索引默认是主键,如果表中没有定义主键,InnoDB 会选择一个唯一且非空的索引代替。如果没有这样的索引,InnoDB 会隐式定义一个主键(类似oracle中的RowId)来作为聚簇索引。如果已经设置了主键为聚簇索引又希望再单独设置聚簇索引,必须先删除主键,然后添加我们想要的聚簇索引,最后恢复设置主键即可。
MyISAM使用的是非聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。
聚簇索引的优势:
(每次使用辅助索引检索都要经过两次B+树查找,看上去聚簇索引的效率明显要低于非聚簇索引,这不是多此一举吗?聚簇索引的优势在哪?)
1.由于行数据和聚簇索引的叶子节点存储在一起,同一页中会有多条行数据,访问同一数据页不同行记录时,已经把页加载到了Buffer中(缓存器),再次访问时,会在内存中完成访问,不必访问磁盘。这样主键和行数据是一起被载入内存的,找到叶子节点就可以立刻将行数据返回了,如果按照主键Id来组织数据,获得数据更快。
(访问聚簇索引字段上相邻的数据更有优势(比如使用orderby grouby (聚簇索引)子句等等)在物理块上也是连续的)
2.辅助索引的叶子节点,存储主键值,而不是数据的存放地址。好处是当行数据放生变化时,索引树的节点也需要分裂变化;或者是我们需要查找的数据,在上一次IO读写的缓存中没有,需要发生一次新的IO操作时,可以避免对辅助索引的维护工作,只需要维护聚簇索引树就好了。另一个好处是,因为辅助索引存放的是主键值,减少了辅助索引占用的存储空间大小。
(当插入或者删除数据的时候,不需要更新辅助索引)
3.因为MyISAM的主索引并非聚簇索引,那么他的数据的物理地址必然是凌乱的,拿到这些物理地址,按照合适的算法进行I/O读取,于是开始不停的寻道不停的旋转。聚簇索引则只需一次I/O。(强烈的对比)
4.不过,如果涉及到大数据量的排序、全表扫描、count之类的操作的话,还是MyISAM占优势些,因为索引所占空间小,这些操作是需要在内存中完成的。
为什么主键通常建议使用自增id
聚簇索引的数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的