索引背后的数据结构

常见查找算法

  • 顺序查找:遍历
  • 二分查找:前提是有序列表
  • 哈希查找:最高效,O(1),hash冲突,JDK1.8里HashMap:数组+链表+红黑树(处理hash冲突)
  • 二叉查找树/二叉排序树/二叉搜索树:二分查找的思想,时间复杂度就是树的深度为logn。缺点:可能会造成树一边倒,时间复杂度变O(n),查找变慢。故演变出平衡二叉树(AVL)
  • 平衡二叉树(AVL树):左右子树高度之差不超过1。
  • 红黑树:高效的查找算法结构
  • B+树
  • B-Tree

MySQL索引背后的数据结构及算法原理:http://blog.codinglabs.org/articles/theory-of-mysql-index.html





红黑树

底层:特殊的二叉查找树
HashMap底层用到红黑树

红黑树的性质

  • 每个结不是红色就是黑色
  • 不可能有连在一起的红色结点
  • 根结点都是黑色的
  • 每个红色结点的两个子结点都是黑色。叶子结点都是黑色。
    在这里插入图片描述




红黑树的变换规则

所有插入的点默认为红色

1 改变颜色

当前结点的父亲是红色,叔叔结点也是红色,

  1. 把父结点变为黑色
  2. 把叔叔结点变为黑色
  3. 把祖父结点变为红色
  4. 把指针定义到祖父结点设为当前要操作的结点

2 左旋

当前父结点是红色,叔叔结点是黑色的时候,且当前的结点是右子树,左旋以父结点作为左旋.

3 右旋

当前父结点是红色,叔叔结点是黑色的时候,且当前的结点是左子树,右旋

  1. 把父结点变为黑色
  2. 把祖父结点变为红色
  3. 以祖父结点作为旋转
    在这里插入图片描述

在这里插入图片描述



数据库查找(B+树) banlance tree

select * from user where id = 100
select * from user where user_id < 100 and user_id > 50

1、为什么红黑树不能作为数据库索引?

数据存放在在磁盘中,通过红黑树对数据检索资源浪费严重.

  1. 读取磁盘的次数太多
  2. 读取浪费太多

2、为什么红黑树可以用在HashMap的查找?

因为HashMap存放的数据放在内存中,不需要经过磁盘.速度快

3、为什么可以用B+树作为索引

B树是N叉树,浪费资源少


B树

BTree有一个非常重要的操作分裂
作为索引的缺点:

  • BTree所有的点都会存数据,会造成空间浪费。范围查找问题没有解决。
    进行范围查找时索引会失效,比如 id<9就要遍历9的所有左子树;

B+树

在B树的基础上给叶子结点加了双向链表的数据结构。
mysql的索引查询原则:最左原则

  1. 叶子结点连起来了
  2. 非叶子节点不存储data,只存储key;叶子节点不存储指针。
  3. 数据和结点一样多

在这里插入图片描述
例如
查找小于9的数,B+数会先找到9这个数,然后利用双向链表遍历左边链表。

如果索引失效,遍历所有结点的情况在B+树上也很简单,找到第一个结点1,然后链表遍历接下来的即可。

如果我们创建了a、b、c作为联合索引 ,相当于创建了(a)、(a、b)、(a、b、c)三个索引

userId + age + name 建了索引
select * from user where age = 1 and name = 1   索引没有生效,全表查询
select * from user where userId = 1 and age = 1 and name = 1 会走索引,因为为三个字段建了索引
select * from user where userId = 1 and name = 1    会走一部分索引(useId)

MyISAM / InnoDM 索引的实现方式

MyISAM索引实现

MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。
MyISAM索引文件数据文件是分离的,索引文件仅保存数据记录的地址。称为非聚集索引
在这里插入图片描述

InnoDB索引实现

区别一:
InnoDB的数据文件本身就是索引文件,如下图,可以看到叶节点包含了完整的数据记录,为聚集索引

在这里插入图片描述
区别二:
InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。例如,图11为定义在Col3上的一个辅助索引:
在这里插入图片描述
回表
在 InnoDB 里,主键索引也被称为聚簇索引,主键索引的节点存的是整行数据。非主键索引也被称为二级索引、普通索引或者辅助索引,非主键索引的叶子节点存的内容是主键的值。根据辅助索引找主键的值,再根据主键找数据,这个操作称为回表


索引优化建议

  1. 为什么不建议使用过长的字段作为主键?

因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。

  1. 为什么用非单调(身份证/学号等非单调递增)的字段作为主键在InnoDB中不是个好主意?

因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。
在使用InnoDB存储引擎时,如果没有特别的需要,请永远使用一个与业务无关的自增字段作为主键。


联合索引在B+树的存储结构

联合索引(col1, col2,col3)也是一棵B+Tree,其非叶子节点存储的是第一个关键字的索引,而叶节点存储的则是三个关键字col1、col2、col3三个关键字的数据,且按照col1、col2、col3的顺序进行排序。
在这里插入图片描述

对应地址指的是数据记录的地址。

如图,联合索引(年龄, 姓氏,名字),叶节点上data域存储的是三个关键字的数据。且是按照年龄、姓氏、名字的顺序排列的。

因此,如果执行的是:

select * from STUDENT where 姓氏='xx' and 名字='xx';
select * from STUDENT where 名字='xx';

结果是无法使用这个联合索引的。因为联合索引中是先根据年龄进行排序的。如果年龄没有先确定,直接对姓氏和名字进行查询的话,就相当于乱序查询一样,因此索引无法生效。因此查询是全表查询。


select * from STUDENT where 年龄=x and 姓氏='x';

那么当执行查询的时候,索引是能生效的,从图中很直观的看出,age=1的是第一个叶子节点的前6条记录,在age=1的前提下,姓氏=’李’的是前3条。因此最终查询出来的是这三条,从而能获取到对应记录的地址。


select * from STUDENT where 年龄=1 and 姓氏='黄' and 名字='安';

索引生效


select * from STUDENT where 年龄=1 and 名字='安';

那么,索引年龄部分能生效,名字部分不能生效。也就是说索引部分生效

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值