mysql索引结构详解

210 阅读4分钟

索引的定义,及数据结构的选用:

mysql索引,就是帮助提高检索效率的排好序的数据结构;

如果没有索引,就需要全表扫描,每次都加载几页数据到内存,然后进行内存数据对比。
全表扫描缺点:1磁盘io次数多;
2 内存数据无序,对比效率低。

针对这种情况,有序的树结构就可以很好的优化这2种情况,备用数据结构:二叉树,红黑树,b树,b+树。

  1. 二叉树:
  • 优势:相比全盘扫描,1二叉树有序,1页节点load到内存之后,如果使用折半查找等算法, 可以加速内存对比效率;
    2二叉树在数据无序的情况下,可以减少磁盘io次数。
  • 缺点:在有序的情况下,会出现单边增长问题。
  1. 红黑树:
  • 优势:相比二叉树,解决了数据有序情况下单边增长的问题;
  • 缺点:在数据量较大的时候,无法控制树高。
    我们知道,树高代表了磁盘的io次数,也是在大数量的时候,性能依然无法保障。
  1. b树:
  • 优势:相比红黑树,b树是一种二叉平衡树,在数据量较大的情况下,解决了树高无法控制的问题。
    此时的数据已经比较完美了。
    但是mysql采用了更优的树结构,b+树。
  1. b+树:
  • 优势:相比b树,1非叶子节点不存储数据,能够存储更多的数据,同时减少了磁盘io次数。
    例如,innob存储引擎默认1页数据16KB,假如使用bigint数据类型,占用内存8B,磁盘地址占用内存6B,那么,1页节点就可以存储16KB / (8KB+6KB) = 1170个元素。
    叶子节点如存储整行数据,1行数据1KB,那么1页节点可以存储16个元素。
    那么,假如树高为3,就可以存储1170*1170*16=2000万个元素,所以,2000千万的数据遍历,只需要3次磁盘Io即可搞定。
    2 叶子节点使用双向指针连接,增加了区间访问的性能。
    例如,查询20<a<50,如果mysql定位到了20,就可以不再遍历索引树,而是直接根据双向指针,加载后面的节点,直到加载到数值为50的元素。
    例如,查询id<20,可以定位到id为20的元素,然后使用双向指针,向前遍历即可。

索引的存储结构:

  • myisam存储引擎
    myisam存储引擎,为非聚簇索引结构,即索引与数据分离。
    /data/tablename.frm文件,存储表结构;
    /data/tablename.myi文件,存储索引,索引叶子节点,存储表数据磁盘地址。
    /data/tablename.myd文件,存储表数据;
  • innodb存储引擎
    /data/tablename.frm文件,存储表结构;
    /data/tablename.ibd文件,存储主键索引树/二级索引树。
    innodb为聚簇索引,主键索引树的叶子节点,存储了整行数据。
    二级索引树的叶子节点,存储了主键索引树中的唯一键。
    通过唯一键为主键id,如果没有主键,mysql会从第1列开始,查找没有重复元素的列来维护索引树,如果没有找到唯一键,则建立隐藏的rowid维护索引树。
    所以使用二级索引树查找非索引列数据,就涉及到回表,即要根据唯一键,去主键索引树的ibd文件中找到整行数据。

为什么使用Innodb存储引擎,推荐使用整形自增类型做主键:

知道了索引树的结构,我们知道在Innodb存储引擎中,mysql默认使用主键维护主键索引树,而索引树是个有序的结构,需要对主键进行排序。
那么

  1. 自增有利排序。
    如有的表喜欢使用uuid做主键,uuid是无序的,在排序上,对比需要消耗时间,
  2. 自增有利索引树的维护。
    在放满元素的b+树的叶子节点上插入1个元素,就需要节点分裂,树重新做平衡。
    而自增的主键,插入元素,只需要在最后1个节点插入元素,或新增元素,向上提本页最小的元素上去即可。
  3. 整型占用空间少
    相比uuid,占用的存储空间更少。

联合索引树的结构:

建立联合索引,首先对a排序,其次b排序,然后c排序,所以a有序的前提下,b才有序,b在索引树的全局并不有序,这也是最左前缀原则的由来。
但是,具体原则又有特殊处理,例如like 'a%',mysql可能会认为是常量,所以也符合最左前缀法则。

hash索引树的结构:

mysql除了可以使用b+树索引结构,还可以使用hash索引。
hash索引支持 = in ,2种查询,效率较高,可以根据col值hash,直接定位数据。但是无法支持范围匹配。