面试官:请你描述一下mysql中索引。
我:哦。。索引大概相似字典中的目录,使用索引可以加快咱们的查询效率。
面试官:还有呢?
我:没了。
面试官:回去等通知。
我:好的。。html
你只看到了索引的第二层,你觉得它在第一层,实际上它是第五层——LOL金牌讲师大司马千层博弈论java
本片文章将从底层数据结构到应用带你了解索引,让你知其然还知其因此然。mysql
类比一下咱们
java
的HashMap
不难理解:
以key-value的形式检索数据,根据索引值生成hashCode,指向具体的行数据面试
这是咱们应用最普遍的索引结构,咱们通常称为B+树,为何称它为B+树呢,咱们来详细分析一下各类数据结构。sql
在线模拟:www.cs.usfca.edu/~galles/vis…数据结构
咱们乱序的插入一些数据
6 3 5 7 8 13 9分布式
可是在极端状况下(按大小顺序插入),可能演变成链表post
假如咱们采用这种数据结构,咱们能够猜测:
在每个节点上会存放:指针
这里穿插一个页的概念: 咱们知道InnoDB(这里不对其余不经常使用引擎展开讨论)中的数据都是存储在磁盘上的,而咱们对数据进行读写时,必需要先将其加载到内存中,InnoDB采起的方式是:将数据划分为若干个页,以页做为磁盘和内存之间交互的基本单位,InnoDB中页的大小通常为 16KB。
反观咱们上文的结构:我查询“3”这条数据须要进行3次查找(io消耗)
经过分裂与合并来保证:分叉数(路数)永远比关键字数多1
如图度数为3的B树,每一个节点(页)最多存储2个关键字,最多拥有3个分叉。
假设:B 树在枝节点和叶子节点存储键值、数据地址、节点引用。
若是咱们B树的路数有1000的话,一颗三层的B树能够存储1000x1000x1000约10亿条数据(在只计算叶子节点的状况下),即只须要最多3次io就能够查到近10亿条的数据。
标准的B+树:
在mysql中,B+索引对标准的B+树作了一些改变:
特色:
每一个节点存储更多关键字
保证每次查询io(次数/耗时/效率)一致
根节点,枝节点不保存完整数据,能保存更多的关键字
范围查询更快,全表遍历更快,只须要遍历叶子节点,不用遍历整棵树
B+树的叶子节点存储的是完整的行记录
由于是完整的记录因此叫聚簇么。。
也是由索引建值构成的B+树,只不过叶子节点只保存了索引建值与主键值
举个栗子:以c列建立的二级索引
在查询条件只包含c时,只过一遍c列构成的B+树便可
查询条件包含c列之外的字段时,须要经过c列的B+树拿到主键值,在走一遍主键的B+树,这个过程也叫回表。
以(a,b,c)三列建立的联合索引,会先根据a排序,若a相等再根据b排序,若a,b相等再根据c排序,来建立一颗B+树
这也是最左匹配原则的由来:只有查询条件里包含(a)(a,b)(a,b,c)列才会走索引,条件前后顺序无所谓,由于mysql会分析各类成本,来选择最优的执行顺序,即只要查询条件符合索引的排序规则。
这个你们都懂,很少BB了
咱们知道B+树维护的是一个从小到大顺序的集合。
对于字符串索引B+树的排序规则:先根据第一个字符排序,若第一个字符相对再根据第二个字符排序。。以此类推。
只有使用“key%”才能根据“key”等值查找到知足条件最小的值,再经过链表向后遍历。
内部维护了一个有序的B+树,若改变其中的大小会致使B+树中大量的页分裂与合并,会形成很大的开销
理由同上,避免频繁的页分裂
咱们知道每个索引都会建立一颗B+树,要排序,插入的效率会很是低
区分度低,查询效率低,还须要维护索引,回表屡次io,不如全表扫描