MySQL基础知识校招面经整理、热身

1. 聚簇索引和普通索引:

聚簇索引指其 B+ 树的叶子节点包含了指向数据的指针。查询聚簇索引时,只需顺着该指针即可访问到数据。
普通索引指叶子节点处的索引项只是存储了某个聚簇索引的索引值,而非直接指向数据。查询普通索引时,还需额外回表 1 次,通过查到的索引值查找该聚簇索引,最终获得数据。
MySQL中 InnoDB 主键索引一定为聚簇索引,不设主键的话第一个唯一索引字段即为聚簇索引,没有唯一索引字段的话,使用隐藏字段自增主键作为聚簇索引。
由于聚簇索引在一张表中最多创建一个,所以其余索引为普通索引。

2. 普通索引和聚簇索引是单独存在表还是另外开一个表:

不太确定这题要问什么。尝试从叶子结点的结构来回答。

  • 聚簇索引的叶子结点是指向了该结点值所在的数据行的,也就是说指向了原数据表。
  • 普通索引的叶子节点则是指向了一个新表,表中存储了当前索引值对应的所有主键值。从这个角度来说,普通索引确实创建了一个新表,而聚簇索引没有(直接在原数据表的基础上以主键构建索引)

3. HashMap 和 B 树有何异同,为什么数据库一般使用b树来当索引:

相同:好像没什么相同。
差异:

  • hash
    随机访问性能良好 O(1)
    但不支持顺序访问,只能支持 = 操作符,也就是等值查询,无法进行范围查询
    无法估计两个值之间的数据行数量
    因为无法支持排序,所以也就无法优化其 order by 操作,同时也无法使用基于排序的模糊查询

  • B 树
    随机访问性能较好 O(logn)
    上述 hash 索引的缺陷 B 树都能克服,因此更适合于数据库的使用场景

4. MySQL 各引擎及其主要区别:

  • MyISAM:5.5 版本前默认存储引擎为 MyISAM,特点是插入、查询较快,支持大文件,采用 B+ 树作为索引结构,崩溃后无法安全恢复。
  • InnoDB:5.5 版本后的默认存储引擎,最大特点是支持事务(即满足 ACID 特性),行级锁、外键、MVCC、采用聚簇索引。
  • Memory:表存放在内存中,提供查询中间结果的高速访问。
  • Archive:支持高并发插入操作,适合用于记录日志等归档数据。

5. 主从复制原理及步骤:

主服务器执行写操作以后,从服务器需要自动将主服务器的数据同步到自己身上。

主服务器运行 binlog 线程,将数据更改写入 binlog 当中。主服务器为每个从服务器创建一个 binlog dump 线程,当 binlog 更新时,该线程通知所有的从服务器进行同步并发送 binlog 给从服务器。
从服务器运行 I/O 线程,读取主服务器的 binlog,并写入从服务器的 relay log 中。
从服务器运行 SQL 线程,将 relay log 中的数据解析出来并在从服务器中重播。

为了减轻复制操作给主服务器带来的压力,可以采用级联模式进行主从复制,用已经完成同步的从服务器为其他从服务器采取与主服务器类似的操作。

6. 回表:

回表即查询非聚簇索引时,叶节点存储的是该数据对应的主键值,需要用此主键值查询主键索引,才能取得对应数据。

7. 覆盖索引:

当所查询的每个字段都包含在索引当中时,查询就不需要回表了,而是可以用这些索引值直接组成查询结果返回。

8. 隔离级别:

  • 读未提交:可以读取到未提交的写 - 脏读、幻读、不可重复读
  • 读提交:可以读取并发事务已提交的写 - 幻读、不可重复读
  • 可重复读:(MySQL 的默认隔离级别,配合 MVCC 和 Next-Key Lock 避免幻读)同一事务对同一字段的多次读结果一致,除非自身进行了修改 - 幻读
  • 串行化:(MySQL 分布式事务下采用)所有事务逐个执行,不会产生干扰

9. 并发事务带来的问题:

  • 脏读:读取到了别的事务修改过的数据,但该事务回滚,修改没有生效。
  • 丢失修改:两个事务都在修改同一字段,先提交的修改被后提交的修改覆盖。
  • 不可重复读:事务内多次读同一个数据,中途这个数据被别的事务修改,导致此事务读到的数据前后不一致。
  • 幻读:类似不可重复读,但不可重复读是对同一数据不同字段的修改,幻读是在原数据之外读到了新的数据行。

10. CAS 和 ABA 问题:

  • CAS 算法就是 Compare & Swap,对某个字段,我们读到了其原值 prev,并计算出需要写入的新值 cur,我们调用 CAS 进行写入,写入前要判断该字段值是否仍等于 prev,若相等则改写并返回成功;否则返回失败。
  • ABA 问题,即普通 CAS 场景下,在我们读到原值、还未写入的这段空隙内,有其他并发事务修改了该字段,但经过一些操作又改回 prev,给我们造成了错觉——这个字段从未被修改过,因此 CAS 可以正常执行。
  • 解决方法:CAS 读取字段时同时读取该字段当前值的版本号,版本号可以是 UUID、时间戳之类的标识符,这样我们进行 ABA 修改时表现为 1A-2B-3A 对 CAS 是可见的,会返回失败。

11. innoDB 为什么使用 b+ 树 而不是 b 树来当索引:

  • b+ 树数据都在叶子节点,都在同一层;而 b 树的数据分布在各层结点中。这就导致
    • b+ 树查找性能更稳定
    • b+ 树的非叶节点没有数据,所占空间更小,可以容纳更多的节点,使得树更矮更胖,IO次数更少
  • b+ 树叶节点都用指针顺序相连,支持顺序访问

12. 乐观锁、悲观锁、MySQL 如何实现:

  • 乐观锁:认为数据一般情况下不会冲突,所以只在修改提交时检测冲突,若冲突则返回错误。
    • 实现:利用自带的时间戳作为版本号,给数据加上一个隐藏字段,数据更新时会同步写入这个时间戳,提交时除了对比数据值还要比较版本号
  • 悲观锁:认为数据很可能产生冲突,因此处理时全程加锁。
    • 实现:使用自带的 for update 语句获得锁

13. MySQL 对事务的实现(ACID):

  • 事务的基本操作是「提交」和「回滚」,MySQL支持事务的这两个功能,主要是通过对 ACID 的实现来保障的。

  • 原子性 Atomicity:原子性是为了保证「回滚」功能能够成功撤销已执行的 SQL 语句,主要依靠 undo log 来实现。回滚时,对 undo log 记载的操作执行相反操作。

  • 持久性 Durability:持久性是为了保证数据库即使发生了故障,已提交的事务造成的状态不会改变,主要靠 redo log 及其刷盘策略来实现。

    • 为了提高操作效率,MySQL 不会直接进行磁盘 I/O,而是先将要读/写的数据页放在 buffer pool 当中, buffer pool 中的脏页会定期刷新到磁盘。
    • 宕机时,buffer pool 中的数据即丢失,需要依靠 redo log 进行恢复。
    • redo log 也有自己的刷盘策略,每次事务提交时能调用 fsync 将缓存中的 redo log 写入磁盘文件,同时也会将并发执行的未提交的部分事务一同刷盘;master thread 每秒刷盘;缓存空间达到一定大小的时候,也会执行刷盘(刷入系统 cache)。
    • redo log 的刷盘是追加操作,每次只增加需要修改的部分(不像数据页刷脏,要将整个页写入硬盘),再加上是顺序 I/O,即使每次事务的提交都至少伴随着一次磁盘 I/O,效率也非常高。
  • 隔离性 Isolation:隔离性是为了减少事务之间的干扰,主要依靠锁、事务隔离级别、MVCC机制来实现。

  • 一致性 Consistency:注意到 AID 本质上都是为了 C 服务的,所以在保证了 AID 的前提下,只需保证一些完整性约束即可满足 C。

n. 题目: