面试题整理(4)

每天五道面试题!只记录答案,不标出源码,有什么不对的地方欢迎评论,共同进步。

1. 什么是B+树?

B+树图样

  B+树是一种树的数据结构(可以类比平衡二叉树),特点是能保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+树元素自底向上插入,与二叉树相反。

  1、非叶子节点不存data,只存key,可增大度。

  2、数据只存在叶子节点。对于MyISAM,叶子节点存指针;对于InnoDB,普通索引叶子节点存主键,主键索引叶子节点存一行数据。

  3、叶子节点本身依关键码的大小自小而大的顺序连接,区间访问性能很好。

相较于B树:

  1、层级更少,因为B+树非叶子节点不存data,只存key,节约了空间,层级少带来的好处就是查询速度更快。

  2、查询速度更稳定,B+树只在叶子节点存放data,所以每次查找的次数相同(I/O次数更少)。

  3、天然排序功能,B+树叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密型很高,缓存的命中率也会比B树好。

  4、全节点遍历更快,B+树遍历整棵树只需要遍历所有的叶子节点即可,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。

相较于Hash索引:

  在数据库中可选的索引一般是两种:B树和Hash索引,Hash索引使用的是Hash算法,查找速度为O(1),但为什么我们一般不会用Hash索引呢?因为我们使用范围查找的时候,比如select * from table where id > 6;,这种查找走Hash索引只能进行全表扫描(可以类比HashMap的key,key是无序的),而对B+树,范围查找就很轻松了。

2. B+树是几层?为什么?

  B+树我们会控制在2到4层,也不一定必须是3层,但3层应该是最普遍的。

  原因:InnoDB的索引节点默认是16K,不存放data只存放key大概能放1170个key,每个key对应一个节点,存放data的话一个节点能放16个。

  假设我们使用了三层树,第一层中每个key对应第二层中的一个节点,也就是说两层中key大概有1170*1170个,第二层中的每个key又对应第三层中节点,一个节点有16个数据,那么总数就是1170*1170*16,大概存储数据在2000万左右。

  根据这个算法我们可以得到2层可以存1.8万左右数据,4层能存百亿数据(基本不太可能用到,千万级别的表效率就比较低了)。

3. InnoDB为什么一定要有主键?为什么要设置成整型的自增主键?

  查看MySql的数据库表文件可以看到,MyISAM有三个文件,分别是.MYD(表数据文件)、.MYI(索引文件)、.frm(表结构文件),MyISAM是非聚集索引,数据和索引分开;而InnoDB只有两个文件,.frm(表结构文件)、.ibd(主键索引和表中数据),InnoDB是聚集索引,主键索引和数据放一起。

  由以上就可以知道,表的存储引擎设计就是这样,InnoDB如果我们不加主键,也会自动生成rowID作为主键,但是这个rowID是全局共享的,6个字节,也就是最大2^48-1,当很多表不加主键时,数据非常多的情况下,是可能出现默认创建的rowID覆盖原有的数据。

  整型的原因就是比较简单,占空间小(相较于UUID来比较,常用的UUID可以缩至16位,里面可能会有各种字母,比较麻烦,需要转换)。

  自增的原因是可以很好的在插入时防止节点分裂,因为B+树自底向上插入,如果在中间的话,很多节点可能都要调整,而自增就可以直接在叶子节点链表最后链上即可,保证了叶子从左到右递增顺序往里放。

4. InnoDB为什么非主键索引结构里叶子节点存储的是主键值?

  1、保持一致性。当数据库表进行DML(增删改)操作时,同一行记录的页地址会发生变化,因为非主键索引保存的是主键的值,无语更改。

  2、节省存储空间。InnoDB数据本身就已经汇聚到主键索引所在的B+树上了,如果普通索引还继续保存一份数据,就会导致有多少索引就要存多少份数据。

5. 回表是什么?(面试官可能会给你一个select语句让你创建索引)

  考虑到普通索引叶子节点存放的是key(索引)和data(主键),我们考虑下边的场景:

  假如使用普通索引进行查找,比如有个学生表,三个字段,id、name、sex,id为主键,name是普通索引,select name,sex from table where name = 'zhangsan';(注意这里是name和sex,如果只是name,结果不同),那么B+树的叶子节点存的就是name(key)+id(data,也就是主键),查到主键后我们还需要再从含主键为索引的B+树搜索一遍。也就是说我们要走两个B+树才可以得到name和sex。回表指的就是这个,走普通索引不能获得我们所需要选的全部数据,必须要通过主键再查一次。

  那如何才能一次就查询到呢,解决方法很简单,建立一个name+sex的索引不就好了!这样普通索引的B+树叶子节点中存的就变成了name,sex(key)+id(data,也就是主键),我们需要name和sex只需要访问一棵树就可以找到,从而避免了回表操作。


PS:索引实际上就像是字典的页码一样,我们先找到偏旁部首多少画,找到页码,而这个页码也只是找到这个这个偏旁的字的相关页码,我们还要通过整个字的笔画去找这个字最终在多少页。
  最左前缀原则也是这么回事,你不可能直接越过偏旁多少画找到这个字在多少页,理解了这个,索引也就很清楚了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值