Mysql面试必知的知识点-干货分享

文章讨论了MySQL中为何选用B+树而非B树作为底层索引,解释了Innodb存储引擎建议设置主键的原因,以及主键为何通常推荐使用整型自增。还提到了除了B+树,MySQL还有Hash索引,但因其不支持范围查询而不常用。联合索引的排序原理和串行化在数据库隔离级别中的实现方式也进行了说明。最后,文章探讨了查询是否需要事务以及大事务可能带来的影响。

底层索引为什么使用B+树,而不用B树?

在这里插入图片描述
在这里插入图片描述

在Mysql内部,对于Innodb存储引擎, 每一个节点都会占一个磁盘页,一个磁盘页的大小默认是16kb.

在这里插入图片描述

也就是说每一个节点存储的东西最多只能有16kb

在这里插入图片描述

那么在b树中,这16kb及需要存储索引,又需要存储真实数据. 而在b+树中,这16kb只需要存储索引, 所以在b+树中一个节点可以存储更多的索引,从整体看, 就会比b树更加的矮胖, 从而可以减少树的深度,减少I/O次数.

为什么Innodb索引建议必须建主键?

首先明确在Innodb索引中, 是依靠B+树来组织整张表数据的, 而默认的话会用主键索引来组织.

那你现在没有主键怎么办?没有索引来组织这个B+树,怎么办呢?

其实Mysql首先会在你的数据表中找,从左往右找,找到一列可以做唯一性索引的, 把该列作为主键,用来维护整张表的数据.建一个B+树.

那如果找不到这列数据呢?Mysql其实还有一个隐藏列->rowid, 这一列对默认递增, 以此作为主键, 用来维护B+树.但其实这种方式并不好,因为我们并看不到这列, 在查询的时候也不能用该列去查询数据.

为什么主键推荐使用整形自增?

这个是两个问题.

1.为什么使用整形?
因为在使用索引查找元素的时候,会进行大量的比较,来确定位置,那如果是整形的话,会效率更高.

2.为什么要自增?
在B+树中,叶子节点是从左到右依次递增的

如果是自增,就只会在叶子节点的最右边新加一个节点即可, 而如果不是自增,就需要根据主键的索引值进行随机插入,那可能就会插入到某个叶子节点的中间位置,此时就需要移动其他数据,甚至需要从一个页面复制到另一个页面,我们将这种情况称为页分裂.页分裂会造成大量的内存碎片,导致结构不紧凑,从而影响查询效率

所以用自增的话,相比来说,效率会更高.

Mysql底层索引只有B+树吗?

其实不是,在Mysql底层,默认是B+树这种索引结构,但其实还有 Hash表,我们也可以选择这种数据结构,但大多数情况下不会使用,为什么?

在这里插入图片描述
Hash结构有它的优点:

  1. 很多时候是比B+索引要快的,更加高效
  2. 只需要一次Hash计算就能定位出数据存储的位置

但是为什么不用呢?

最主要的点就是不支持范围查询, 而在我们业务中,范围查询是一个非常常见的需要, 而B+树就可以很好的范围查询.

联合索引底层长什么样子?

联合索引是一个非聚集索引.如下:
使用name、age、position三个字段建立联合索引
在这里插入图片描述
在排序的时候,先按第一个字段name排,第一个字段相同的时候才按第二个字段age排序,第二个字段相同的时候按照第三个字段position排序. 这也是为什么会有最左前缀匹配原则

数据库隔离级别中串行化是怎么实现的?

这个其实很简单,所谓串行化, 就是把所有的涉及到相同数据的读写, 写写的这些操作全部串行.读读是不影响的.

比如说A事务先读取一条数据, select * from user where id=1;但是A事务还没有提交
此时B事务去更新update user set name=‘a’ where id=1;会是什么效果?

此时B事务就会被阻塞住,直到A事务提交之后.
要实现这种效果其实非常简单,就是对所有的读操作都加上读锁, 也就是都变成当前读, select … lock in share mode;

查询方法需要加事务吗?

在我们的Java项目某个方法中,只有查询操作,这个查询可能有多个, 这个方法需要加事务吗?

要理清楚这个问题,首先要明白 加事务查询和不加事务查询的区别:

快照读:

  • 不加事务: 读取的都是所有事务已经提交的数据.
  • 加事务: 和事务对应的隔离级别有关系,
    1. 读未提交: 可能读到其他事务未提交的数据
    2. 读已提交: 读取到的是所有事务已经提交的数据.
    3. 可重复读: 可能读取到的可能是历史数据,因为在当前隔离级别中, 所有读取的数据都来自开启事务后第一次读取的快照数据.
    4. 串行化: 读写操作,写写操作会被阻塞.

当前读:

  • 因为当前读是相当于加读锁的,所以对于当前读, 不加事务和加事务在所有情况下效果都是一样的.

我们平常大部分查询都是快照读, 事务的隔离级别大部分都是读已提交或者可重复读.接下来我们再重点说下这两种情况:

快照读-读已提交:
这种情况下其实不需要加事务读了,因为加事务读和不加事务读取到的结果都是一样的, 都会读取到其他事务已经提交的最新数据.

快照读-可重复读:
这种情况下就有区别了, 具体需要根据业务场景判断加不加,举个例子:

  • 比如说需要生成报表, 那报表其实就需要的是某个时间点的数据, 也就是某个版本的快照数据, 因为要保证数据整体上的一致性.所以就需要加事务去读.
  • 比如说某个场景就需要最新的数据, 那就最好不加事务,这样读取的就是所有事务已经提交的最新数据.

大事务有什么影响?

  1. 并发情况下, 数据库连接池容易被撑爆
  2. 大事务一般当前读会比较多, 容易造成大量阻塞和锁超时
  3. 执行时间长, 容易造成主从延迟
  4. 回滚需要的时间比较长
  5. undo log日志膨胀

今天的分享就到这里了,有问题可以在评论区留言,均会及时回复呀.
我是bling,未来不会太差,只要我们不要太懒就行, 咱们下期见.
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员bling

义父,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值