InnoDB 系列文章目录
1.InnoDB的关键特性
2.InnoDB的存储结构
3.InnoDB的索引和算法
4.InnoDB的锁总结
5.InnoDB的事务
索引是数据库中非常重要的元素,用得好可以极大的提升查询效率,用不好却可能导致更新插入时,发生很多次IO,导致效率低下。
索引中的算法
索引属于算法中经典的检索数据问题。当讨论索引的算法时,也许都会想起B+树,但是除了B+树,实际上还用到了二分查找和哈希算法。
二分查找
为什么要使用二分查找,一个关键的原因是,索引并没有找到数据在哪一行,而是找到数据所在的页,并把数据加载到内存查找。由于页内的数据是排好序的,所以使用二分查找效率就非常高。
//对数组进行二分查找算法
public Integer dichotomy(int[] nums,int target){
if(nums==null||nums.length==0){
return null;
}
int left =0;
int right = nums.length-1;
while(left<right){
int min = (left+right)/2;
if(right-left==1){
if(nums[left]==target){
return left;
}
if(nums[right]==target){
return right;
}
break;
}
if(nums[min]==target){
return min;
}
else if(nums[min]<target){
left = min;
}else{
right = min;
}
}
return null;
}
B+树
定义
B+树的定义和描述很复杂,但是使用一张图却能够清晰的理解
这里有几个关键点
- B+树是一个多叉树
- 每个节点都是有序的
- 只有叶子节点才存放数据,其他节点存放指向下一层索引或者数据的指针
- 叶子节点使用指针关联起来,这样自如果使用范围查询,效率将非常高。
B+树的增删
B+树增加数据时会判断,叶子节点是否已满,如果叶子节点已满,就会取出中间的值,并把小于中间值和大于等于中间值的数据拆分成两页,并把中间的值提升到上级索引,如果上级索引页也满了,会递归操作,直到全部满足条件。
B+树删除时,和增加时类似,不过考虑的是填充因子(数据占页的比例),如果填充因子小于50%,那么InnoDB就会尝试把该节点和旁边的节点进行合并,如果合并成功,就会删除上级索引。如果上级索引的填充因子页小于50%,就会触发递归操作。
可以看出,在糟糕的情况下,B+树的增删是会耗费一些时间的。
哈希算法
InnoDB中除了B+树索引,还有自适应哈希索引,InnoDB会把热点数据自动的加入到哈希索引中。哈希算法很经典,其实页很简单。就是把索引的key值转换成整数,并使用取余算法,把每个整数对某个质数取余,根据取余得到的值,把数据分配到不同槽中。比如假如质数选为3,那么就有3个槽,9%3=0,分配到第一个槽,4%3=1,分配到第一个槽。
但是如果,取余得到的槽是一样的怎么办?这种情况称之为哈希冲突,InnoDB使用链接法,即每个槽保存的是链表,冲突的数据就加入到链表中。和java中的哈希表不一样的是,java中的哈希表中的链表会在链表的长度达到8时变成红黑树,而InnoDB并没有这样操作,我猜可能是热点数据并不会很多吧。
索引
聚集索引和非聚集索引
我们知道,InnoDB中的数据是按照主健索引来存储的,实际上,数据页就是B+树中的一个叶子节点,索引页就是B+树的非叶子节点。把这种索引称之为聚集索引。由于聚集索引跟数据的排列关系有关,所以一个表只有一个聚集索引。所以使用聚集索引检索是最快的。
另外,在上面提到B+树的时候,相邻的叶子节点是互相链接的,所以使用聚集索引进行范围查找效率非常高,只有找到范围开始的页,然后顺序遍历到范围结束的页即可。
非聚集索引(也称辅助索引)一个表可以创建多个,非聚集索引是单独存储的,跟数据的排序无关,也是使用B+树的结构,不同于聚集索引的是,非聚集索引的叶子节点存放的不是数据,而是主健索引。所以在使用非聚集索引之后,还是会调用聚集索引找到真正的数据所在页。
联合索引
联合索引是指把多个字段联合成一个索引,InnoDB会依据字段的顺序进行组合。
值得注意的是,索引的第二个字段会被排序存储,也就是说,如果使用第一个字段进行分组,第二个字段作为组内的排序,数据库就不需要进行一次排序了,这提高了检索效率。
自适应哈希索引
自适应哈希索引是InnoDB提供一种不能人为干预的索引,InnoDB会自动的发现热点数据,并存放到哈希索引,这样只需要O(1)的时间就能查到数据,但是哈希索引只能用于等值,即age=18,而对age<=18不起作用。
索引生效和失效条件
即使建立了索引,数据库页不一定会使用索引。比如说,检索的数据预估超出全部数据的20%。这时候会使用全表扫描而不是索引。
在以下条件也会导致索引失效
- 使用or 且 包含无索引的字段
- like插叙以%开头
- 查询字段未字符串类型,但是未使用引号包括,如a=123,a=‘123’
- where条件进行运算
- 单独使用联合索引中的非第一列字段