每日八股文6.6

发布于:2025-06-07 ⋅ 阅读:(20) ⋅ 点赞:(0)

Mysql

1.怎么查看一条sql语句是否走了索引?

在这里插入图片描述
最常用的方法是使用explain命令,在待执行的sql语句最前面加上explain,这样做会返回一个执行计划,而不会真正的去执行这条命令。
我们分析这个执行计划需要重点关注以下几个字段:

  1. type:他表示mysql的访问方法,如果这个字段显示的不是ALL或者Index,那么通常就说明使用了索引。
  2. possible_keys:这个字段的值表示的是可能使用的索引,可能会有多个。
  3. key:表示实际用到的索引,如果这个字段的值为null,表示没有用到任何索引。
  4. key_len:表示实际用到的索引的长度。
  5. rows:表示估计需要扫描的行数,如果使用了索引的话,这个值应该比全表扫描要小很多。

2.能说说 MySQL 事务都有哪些关键特性吗?

在这里插入图片描述

  • 原子性A:定义在事务里面的操作要么全部执行,要么全部都不执行。原子性是由undo_log实现的,undo_log会在事务执行的时候存储和当前操作对应相反的操作,以便于之后恢复到原始状态。
  • 持久性D:如果我们执行了事务的所有操作,那么他对数据库的影响是永久的,就算这些操作的结果现在还未被写入磁盘,依然可以保证这一点;这是通过redo_log实现的,这里面记录了事务所做的所有操作,在系统恢复时也可以重新执行。
  • 隔离性I:允许多个事务并发操作,在多个事务进行并发操作同一个表时,该表不会产生不可预测的后果。隔离性主要是通过MVCC和锁实现的。
  • 一致性C:执行完事务的所有操作后,原数据库的完整性约束不可以发生改变。这条性质与前面三条息息相关,只要实现了原子性、持久性和隔离性,那么也就实现了一致性。

3.MySQL 是如何保证事务的原子性的?

Mysql是通过undo log来保证事务的原子性的。当我们在执行事务中的对应操作时,undo log会记录与当前操作相反的操作,比如,我们在事务中执行了insert,那么在undo log中就添加一条delete;如果我们执行update,那么在undo log中就会记录更新前的值。

如果在事务的执行过程中出现了错误或者显式的使用rollback回滚操作,那么就会根据undo log中记录的操作,从后往前执行(逻辑上是栈,但实际存储结构是链表),这样就可以恢复到事务未开始前的数据。

4.MySQL 是如何保证事务的隔离性的?

保证事务的隔离性是通过mvcc和锁协同实现的。

mvcc用来保证读写分离。当一个事务在读数据,一个事务在写数据时,读数据的事务会维护一个历史版本的数据快照,这样可以保证不会读到脏数据(即另一个事务写的数据),其次,这样还可以避免不可重复读的问题,即保证了每一次读的结果都是相同的。

锁用来保证写写分离。当多个事务都在写同一份数据时,只有一个事物可以获得对数据的实际操作权,其他事务想要写必须得等到锁的释放。Mysql提供了不同粒度的锁,比如行级锁和表级锁,可以根据具体的情况来添加锁。

5.能简单介绍一下 MVCC 吗?或者说,你理解的 MVCC 是什么?

MVCC的全称是多版本并发控制(Multi-Version Concurrency Control),是一种高并发数据库系统中的事务隔离技术。
我理解的MVCC就是在实现事务隔离的基础上,进一步提升并发能力。传统的隔离技术比如锁,在并发读写时不可避免地会阻塞;MVCC通过维护多个版本的数据,实现了并发读写,从而很大程度的提高了吞吐量。

6.事务的持久性又是如何保证的?

Mysql的InnoDB引擎使用WAL(write ahead logging)和redo log 来保证事务的持久性,即先写日志,再写数据。
在进入事务执行真正的操作前,会将执行的操作同步写入redo log的缓冲区和buffer pool内存缓冲区,当事务提交时,会以追加写的方式写入到redo log中,这个速度非常快;现在即使buffer pool中的一些数据并没有写入到数据库中(可能因为数据库或服务器原因),那么之后也会根据redo log日志记录的操作重新按顺序执行,这样就保证了事务的持久性。

7.MySQL 都有哪些事务隔离级别呢?它们分别解决了哪些并发问题?

在这里插入图片描述
Mysql的事务有四大隔离级别,分别是读未提交,读已提交,可重复读和串行化。

  1. 读未提交:这是最低的隔离级别,在这个级别下,mysql可以读取其他尚未提交的事务所做出的修改,会导致读取脏数据的问题,该级别在实践中基本不会使用。
  2. 读已提交:在这个级别下,mysql只能在其他事务已经提交后的数据,这避免了读取脏数据的问题,但是没有解决可重复读的问题,因为重复读的情况下,可能每次读取到的数据都不一样(因为其他事务做出了修改)。
  3. 可重复读:这是mysql的默认事务隔离级别,在这个级别下,mysql通过mvcc和锁成功避免了前面的两个问题,但如果是当前读(读取数据的最新版本),那么可能会出现幻读的情况,即多次读取的结果行数不一致;InnoDB引擎通过引入next-key locks机制很大程度避免了这个问题。
  4. 串行化:这是最高的事务隔离级别,即完全摒弃了并发,只能一个事务一个事务的执行,这种级别严格保证了数据一致性,但是效率非常低。

补充关于当前读:
在这里插入图片描述

8.MySQL 默认的事务隔离级别是什么?它是怎么实现的呢?

可重复读隔离级别主要是通过 MVCC(多版本并发控制)机制来实现对普通 SELECT 查询的隔离性。在 MVCC 中,每一条记录都可能存在多个版本,每个版本都与创建它的事务 ID 相关联。当一个事务启动时,会创建一个 Read View(读视图),这个 Read View 会记录当前所有活跃的事务 ID。

当事务执行 SELECT 查询时,会根据 Read View 中的信息以及记录的版本号来判断哪些版本的数据是可见的。简单来说,事务只能看到在它启动之前已经提交的事务对数据的修改,以及当前事务自身所做的修改。在可重复读隔离级别下,Read View 通常在事务中的第一个 SELECT 语句执行时创建,并且在整个事务执行期间都会复用这个 Read View,这就保证了在同一个事务中多次读取同一份数据时,得到的结果是一致的,从而避免了不可重复读的问题。

对于执行 UPDATE、DELETE、SELECT … FOR UPDATE 等当前读的操作,MySQL 会使用行级锁来保证隔离性。在可重复读隔离级别下,InnoDB 会使用Next-key locks来避免幻读。

9.你了解读已提交和可重复读这两种隔离级别在使用 MVCC 实现时有什么区别吗?

这两种隔离级别在使用MVCC实现时的主要区别就是创建read viev的时机不同。

在读已提交这种级别,每次执行select查询语句时都会创建一个read view,所以我们每次查询的结果有可能是不同的,因为这中间有可能有其他事务对这部分数据做了修改。

在可重复读这种级别,只会在第一次执行select语句时创建一个read view,在该事务的后续查询中,每次都使用的是这唯一一个read view,所以每次查询的结果都是相通的。

10.redo log 是怎么实现持久化的?

在事务提交时,对数据页的修改是先写入到buffer pool内存缓冲区中,再写入到磁盘中去的,不是直接写入到磁盘中去(考虑到内存写入速度更快)。所以说,如果没有redo log,如果在刷盘的过程中出现了数据库服务器故障,那么就无法实现持久性。

所以引入了redo log,在执行事务中的操作时,把操作同步写入到redo log的缓冲区及buffer pool,事务提交时,先写入redo log,再刷盘,这样如果说我们在刷盘的过程中遇到了服务器故障,后面也可以通过redo log里面的内容进行重写,这样就实现了持久化。


网站公告

今日签到

点亮在社区的每一天
去签到