MySQL索引实现方式有:B+tree索引、Hash索引、Full-text索引。我们最常用的是B+tree索引,主键索引(也叫聚簇索引)本身就是一个B+tree索引树,非叶子节点存储主键id,叶子节点为一整行数据,叶子节点之间通过双向链表连接支持范围扫描。
一、mysql索引是怎么实现的
MySQL索引有哪些实现方式
MySQL索引实现方式有:B+tree索引、Hash索引、Full-text索引。
我们最常用的是B+tree索引,主键索引(也叫聚簇索引)本身就是一个B+tree索引树,非叶子节点存储主键id,叶子节点为一整行数据,叶子节点之间通过双向链表连接支持范围扫描,一般加的少数索引,普通索引都是B+tree索引。
Hash索引只能在memory存储引擎下使用,这里不过多描述,优点是查询快,hash取模O(1)检索,缺点不支持范围查询,出现hash冲突性能会降低。
Full-text索引主要对varchar,text加索引,使用倒排索引的方式,与搜索引擎实现方式相似。
为什么使用B+tree索引
先说结论,主要因为磁盘读写速度远远低于内存速度,传统的机械硬盘大概慢一万倍,固态硬盘慢100倍,故减少磁盘I/O次数是提升索引性能的重点。
根据局部性原理和磁盘预读,Linux操作系统进行磁盘I/O时,一般顺序读写4KB到内存的Page Cache中,之后再在内存中找到对应的数据返回回去,Mysql的B+tree每个节点为16KB,我们可以把16kb当作磁盘IO的最小单元。
局部性原理表现为:时间局部性和空间局部性。时间局部性是指如果程序中的某条指令一旦执行,则不久之后该指令可能再次被执行;如果某数据被访问,则不久之后该数据可能再次被访问。空间局部性是指一旦程序访问了某个存储单元,则不久之后,其附近的存储单元也将被访问。
那么为什么选择B+tree作为索引呢,B+tree降低了磁盘IO次数吗?为什么不用红黑树或者hash索引呢。
红黑树每个节点容纳1个key,树的高度为O(log➋ N),查询复杂度也是O(log➋ N),1000000条数据,树的高度为1000,最差需要扫描1000次才能查询到对应数据。
B+tree每个节点容纳M个key,树的高度为O(logm N),m越大,树高度越低,按照mysql一个page节点存储16kb来算,一个bigint主键是8个字节,一个节点可以容纳大概1000个主键(每个节点还存储了其他隐藏信息帮助节点内部检索),m就是1000,一千万条数据,树的高度大概是3层,只需要3次磁盘I/O加上几百次内存遍历查找,就可以快速定位到数据,这对查询性能的提升的巨大的,如果没有索引而进行全表扫描的话,大概需要上万次磁盘I/O。
故基于局部性原理和磁盘预读,B+tree适合在磁盘文件系统中做检索,红黑树更适合在内存中检索(比如java的hashmap,网络epoll的连接节点存储)。
为什么推荐使用自增ID作为主键呢,B+tree的构建过程是通过分裂和合并保持树的稳定的,如上图,若不是顺序插入的,树会进行频繁的分裂,导致额外的磁盘IO和CPU使用,可以使用此网站数据结构构建过程手动测试下。
另外mysql的除主键外的普通索引的叶子节点都是id,故id越小普通索引的占用磁盘空间越小,故推荐使用int或bigint来做主键(下文详细讲)。
延伸阅读:
二、索引分类
索引按照索引列是否是主键,分为主键索引和辅助索引(除主键列索引外,其他列的索引都是辅助索引)
辅助索引又可分为少数索引,普通索引,全文索引
主键索引:即主索引,根据主键建立索引,不允许重复,不允许空值;
少数索引:用来建立索引的列的值必须是少数的,允许空值;
普通索引:用表中的普通列构建的索引,没有任何限制;
全文索引:用大文本对象的列构建的索引,在MySQL5.6以下,只有MyISAM表支持全文检索。在MySQL5.6以上Innodb引擎表也提供支持全文检索。