MySQL学习总结 - 常见的索引模型
作者:互联网
MySQL学习总结 - 常见的索引模型
索引一句话简单说,就是为了提高数据查询的速度,类似于书的目录,例如文章上面开头的目录结构。
hash表
哈希表是一种key-value的结构,通过hash函数将给出的key计算出value值需要存放的位置,再将value值放入数组对应位置中。当然不可避免,不同的key通过hash函数会得到相同的值,出现hash冲突。一种做法是直接采用拉链法更多见附录,即hash函数的结果相同value,通过链表串联起来,保存在数组的对应位置。
例如,以通过id_card作为key值存储到hash表中。如下图所示,key: ID_card_n1通过hash函数计算出下标为M,所以将其对应的User1存储到数组下标为M中。而ID_card_n2和ID_card_n3计算出来的结果都是N,所以将User2和User4通过链表链接起来,保存在数组下标N的位置中。而链表中的做法是直接追加到尾部,没有进行排序。
当需要通过key值查询时,直接通过hash值计算下标即可。如果存在hash冲突,再遍历链表,挨个比较key值进行匹配。例如通过ID_card_n2搜索时,首先计算下标为N,发现存在hash冲突,这遍历链表比较key值,匹配到User2。
优点:
能够通过主键快速定位,能够通过hash值快速定位记录位置。当出现hash冲突时,通过拉链法解决。在等值查询时很优秀。
缺点:
在范围查询时很麻烦,例如要查询id在[1, 1000]内的所有数据,需要遍历hash范围内的所有值,挨个去查询,效率很低
所以哈希表在等值查询中表现很优秀,适用于Memcached等一些NoSQL使用
有序数组
有序数组通过Key进行升/降序排序。保证主键唯一的前提下,当等值查询时,直接通过二分查找法,即可快速定位,时间复杂度为\(O(log(N))\)。范围查询时,可先通过二分法找到左边界所在位置,再向右遍历比较右边界即可。
依旧以上面的案例为例子,有序数组对应的图如下:
当要找到key值为ID_card_n4时,直接二分查找即可定位。当要找出[ID_card_n4, ID_card_n2]之间所有元素时,首先通过二分法找到ID_card_n4所在位置,再向右遍历,挨个比较key是否为ID_card_n2,找到即停止遍历,也可以快速找到所有的元素。
单看查询效率来说,有序数据的效率无疑很高,但是当存在数据量变动就效率很低了。如果要在中间插入或者删除元素,无疑是致命的。删除可以通过加入标志位进行规避,但是在插入时,还是需要将后面的元素向后挪动一位,这效率太低了。
优点:
对于等值查询,通过二分法可快速定位位置,时间复杂度为o(log(N))
对于范围查询,通过二分法来查询到左边界条件后,向右边界条件直接遍历获取即可
缺点:
当有数据插入数组中间时很繁琐,需要挪动数据,再能进行插入操作。
所以有序数组对于静态数据存储很友好,例如2021年安徽省各市的天气信息。这种数据不会存在修改的场景。
二叉搜索树/平衡二叉树
上面的场景,通过二叉搜索树即可得到下面的图。二叉搜索树的特点:左孩子<父节点<右孩子
如图要找ID_card_n2时,路径如下: UserA -> UserC -> UserF -> User2,此时时间复杂度为\(O(log(N))\)。
二叉搜索树存在一个问题,数据恰好是有序的,这二叉树会退化为一个链表,导致查询时时间复杂度升为\(O(N)\)。二叉搜索树最好的情况就是恰好是一颗平衡二叉树,此时的时间复杂度即为\(O(log(N))\)。当然平衡二叉树更新时需要维护树的结构,更新的时间复杂度也为\(O(log(N))\)。
但是二叉搜索树&平衡二叉树在存储引擎中并不常用,因为索引还需要落到磁盘中。如果有100W条数据需要建立索引,那么对于100W个节点的平衡二叉树,树的高度就有20层。意味着需要从磁盘至少读取20次数据块,假设我们读取一次硬盘的速度为10ms,\(20 * 10 = 200\)ms,这个查询效率无疑并不高效。所以更多的采用N叉树来压缩树的高度,以减少读取磁盘的次数,提升查询效率。
标签:hash,模型,查询,索引,二叉树,key,MySQL,ID,card 来源: https://www.cnblogs.com/toughtful/p/16242865.html