MySQL面试题总结

x33g5p2x  于2021-10-21 转载在 Mysql  
字(1.7k)|赞(0)|评价(0)|浏览(503)

数据库设计的初衷是处理并发问题。

1. MVCC是什么,怎么实现的?

MVCC是多版本并发控制,是InnoDB存储引擎为了实现对“事务”的支持而实现的一种机制,可以将其看作是行级锁的一个变种,但是可以在很多情况下避免加锁操作,开销更低。

MVCC的具体实现:

  1. 每个事务都有一个由系统分配的id:transaction_id;单调递增,系统内唯一;
  2. 每一行数据都有一个隐藏的列:row_trx_id,用于记录操作这行数据的事务的id,每一行数据都都有多个版本,它们组成一个“链表”式的结构,称为“undo log”;

在实现上,InnoDB为每个事务在开始时构造一个“数组”,其中保存在这个事务启动瞬间正在活跃的所有事务ID(所谓“活跃”指的是“启动了还未提交”)。

↓当前事务
[已提交事务] [      数组      ] [未开始事务]
	       低水位         高水位
  数组中的事务id最小值     数组中的事务id最大值

通过这个数组,生成了 当前事务的“一致性视图”。

视图数组将每个行数据的 row_trx_id 分成了三种不同的情况:
(1)
(2)
(3)

MVCC中的读和写操作:

在MVCC中,读操作是“快照读”,写操作是“当前读”。
更新数据都是先读后写,这个读必须是当前读。

MVCC对于RC和RR的区别:

在InnoDB中,“RR(可重复读)”和“RC(不可重复读)”都是通过MVCC实现的,区别在于:

RR:只在事务开始时生成一个一致性视图(就是那个以数组为基础的+低水位、高水位的视图),所以RR在事务过程中可重复读;

RC:每次语句执行前,都会生成一个一致性视图,所以RC在事务过程中是不可重复读。

MVCC中的读操作如何进行“当前读”:

MVCC中的读操作默认都是“快照读”的,如果想要进行当前读:

select * from 'table_name' lock in share mode;	//共享锁
select * from 'table_name' for update;			//排他锁

事务开始的时间:

启动一个事务时,begin或者start transaction命令并不是一个事务的起点,执行到第一个操作InnoDB表的命令时才是,
可以强制在begin时开启事务:

begin with consist...

幻读和间隙锁:

在InnoDB中,幻读只会出现在“当前读”时,快照读不会出现幻读。

InnoDB解决幻读的方法是加 “gap lock” 间隙锁。

2. MySQL中的锁:

分三种:
全局锁、表锁、行级锁

表锁:

分两种:

  1. 表级锁:
  2. 元数据锁:
//表级锁:
lock table read;
lock table write;

//元数据锁:
//1. 当执行select 查询时就会加锁元数据锁,避免有人增加或删除列:
//2. 如果【在事务中】执行alter table ... add column_table ,会触发事务自动提交,导致事务无法回滚

alter table 'table_name' add column 'column_name';	//加元数据锁
select * from 'table_name';	//加元数据锁

3. MySQL的两阶段提交:

“先写日志,再写磁盘”,
这样做的目的是为了提高MySQL的性能,在空闲时进行写磁盘的操作。

但这样做引入了一个问题:crash-safe。
如果内存中的数据还没来得及写盘的时候就发生了宕机或进程crash,就会造成数据丢失。

以前的MyISAM 存储引擎是不支持crash-safe的,InnoDB支持。

MySQL Server层实现了binlog,InnoDB实现了redo log,
redo log是循环写,binlog是追加写,
所以在宕机恢复后只要恢复redo log中的内容就可以了。

redo log也是要写磁盘的。
具体咋实现的???

主备同步的过程:

redo log ----> binlog ----> relay log

4. 为什么用B+树而不是二叉树、B树:

二叉树:减少读磁盘的次数

B树:B+树只在叶子节点上存储元素,B+树中存储在叶子节点上的数据都是按顺序防止的【双向链表】,更适合做范围查找;而B树上的所有节点都可以存储元素,当进行范围查找时,会涉及到回溯,增加了实现的复杂度。

相关文章