每日问答中间件篇

每日问答mysql篇

1.InnoDB 为什么选用 B + 树做索引,而不用 B 树、哈希索引?

InnoDB 选用 B + 树:①非叶子节点只存索引键,一页存放更多索引,树矮,磁盘 IO 少;②叶子节点双向链表,非常适合范围查询、排序;③B 树叶子没有链表,范围查询性能差;hash 索引等值查询快,但不支持范围、排序,还有哈希冲突。

2.什么是聚簇索引、二级索引?什么叫回表?什么是覆盖索引,覆盖索引如何避免回表?

聚簇索引就是主键索引,叶子节点存放整行数据;二级索引叶子存索引列 + 主键。通过二级索引拿到主键,再去聚簇索引拿完整行就是回表。覆盖索引,查询字段全部在二级索引中,无需回表。

3.请讲联合索引最左前缀原则,并且说出几种索引失效的场景?

联合索引 (a,b,c),索引排序顺序 a→b→c。查询必须匹配最左边的起始列,才能用上索引。

例:where a=? 能用;where a=? and b=? 能用;where b=? 不能直接走联合索引,跳过最左 a,索引失效。
失效场景汇总:

①索引列做函数、运算;②like 以 % 开头;③隐式类型转换;④not in、!=;⑤or 一侧无索引;⑥违背最左前缀。

4.MVCC 有哪几个核心组成?快照读、当前读分别对应哪些 SQL?

完整 MVCC 三大核心组成:

  1. undo log:保存数据历史版本,构建版本链
  2. 行隐藏字段trx_id(最后修改事务 ID)、roll_pointer(指向 undo 上一个历史版本指针)
  3. Read‑View 读视图:控制我能看到哪些版本的数据(RC/RR 最大区别就在 Read‑View 生成时机)

快照读:普通select * from table,读取 undo 版本链历史快照,不加行锁。

当前读:select ... for update / select ... lock in share mode / update / delete,读取最新数据,会上锁。

💡短句总结:

MVCC 三要素:undo log、行隐藏字段 trx_id 与 roll_pointer、Read‑View。快照读普通 select;当前读是加锁查询以及 update、delete 语句。间隙锁属于锁体系,不属于 MVCC。

5.RC 读已提交 和 RR 可重复读,MVCC 的 Read‑View 生成时机有什么区别?RR 级别是怎么解决幻读的?

1.Read‑View 生成时机(RC vs RR)

  • RC(读已提交):每执行一次普通 select,就生成一个新 Read‑View
    每次查询都拿最新视图,所以能看到别的事务已经提交的数据,会出现不可重复读,同一个事务内两次 select 结果不一样。
  • **RR(可重复读,InnoDB 默认):事务开启之后,**第一次执行快照读 select 的时候生成一次 Read‑View,整个事务复用这一个视图 **。
    整个事务全程用同一个 Read‑View,所以同一个事务多次 select 读到的数据不变,实现可重复读。

记忆口诀:RC 每次查询新建视图;RR 事务第一次 select 生成,全程复用。

2.RR 怎么解决幻读(高频大坑)

幻读:同一个事务,两次当前读,中间别的事务插入新行,第二次读到多出的行。

分两层:

  1. 快照读(普通 select):靠 MVCC 的 Read‑View,读取历史版本,看不到别人新插入的数据,快照读没有幻读。
  2. 当前读(update/delete/for update):MVCC 管不住,会产生幻读。InnoDB 使用 Next‑Key 临键锁 (记录锁 + 间隙锁),锁住扫描到记录以及记录之间的间隙,禁止其他事务在间隙插入数据,解决当前读幻读。

⚠️:RR 不是单靠 MVCC 解决幻读;快照读靠 MVCC,当前读靠临键锁,两者配合才解决幻读


极简口述答案

RC 隔离级别,每一次 select 都会生成新的 Read‑View ;RR 隔离级别,事务第一次快照读时生成 Read‑View,整个事务复用同一个视图

RR 解决幻读分为两部分:快照读依靠 MVCC 的 Read‑View 读取历史快照避免幻读;而 update、delete、for update 这类当前读,依靠 Next‑Key 临键锁锁住间隙,阻止其他事务插入新数据,解决当前读的幻读。

6.ACID 四个特性分别依靠 InnoDB 哪些机制来保证?redo log、undo log 各自作用是什么?什么是 WAL?

  1. ACID 四个特性,分开对应底层机制
  • A 原子性:事务要么全成要么全失败 → undo log,失败回滚
  • C 一致性:是最终业务结果,不是某一个组件直接实现,原子 + 隔离 + 持久共同保障
  • I 隔离性:多个事务之间互不干扰 → MVCC + 锁体系(行锁、临键锁等)
  • D 持久性:事务提交后数据永久生效,宕机不丢 → redo log
  1. redo log:记录数据页修改之后的物理日志,宕机恢复用。事务提交,redo log 刷盘,保证崩溃之后可以恢复已提交事务。
  2. undo log:保存数据修改前的历史版本,用于事务回滚 + MVCC 生成版本链,不是简单事务操作日志。
  3. WAL:Write‑Ahead‑Log 预写日志。修改数据页之前,先把 redo log 写入磁盘,再更新内存的数据页,晚一点再刷脏页到磁盘。不是先写缓存再落盘。

✅精简口述版:

A 原子性由 undo log 实现,事务失败可以回滚;D 持久性依靠 redo log;I 隔离性靠锁和 MVCC;C 一致性是业务最终结果,由 AID 共同保证。

redo log 记录数据页物理修改,用于崩溃恢复;undo log 保存修改前数据,用于回滚和 MVCC 版本链。

WAL 预写日志机制:修改内存数据页之前,先把 redo log 持久化磁盘,脏页可以后续慢慢刷盘。

7.Record 记录锁、Gap 间隙锁、Next‑Key 临键锁分别是什么?什么场景会产生间隙锁?

前提:只有 RR 可重复读隔离级别才会出现间隙锁、临键锁;RC 没有间隙锁,只有记录锁

  1. Record 记录锁(行锁)
    锁住已存在的某一行真实记录。只锁这条数据,不让别的事务修改删除。
  2. Gap 间隙锁
    锁住两条记录中间的空隙,不锁记录本身。目的:禁止其他事务往这个间隙插入新数据,防止幻读。

间隙可以是:索引最前面、两条记录中间、索引最后面之后。

  1. Next‑Key Lock 临键锁 = Record 锁 + Gap 间隙锁
    InnoDB RR 下默认的行锁算法。既锁住当前这条记录,同时锁住这条记录前面的间隙,防止插入。

什么时候产生间隙锁

  • RR 隔离级别;
  • 使用当前读:update / delete / select ... for update;
  • 查询条件走索引,条件命中不到真实存在的数据,就会产生间隙锁;

举例:表 id 有 1、5、10;执行 update set name=? where id=7,7 不存在,会锁住 5‑10 这个间隙,其他事务不能插入 id=6,7,8,9。
重点坑:RC 隔离级别没有间隙锁,所以 RC 无法解决当前读幻读。

精简短句

Record 记录锁:锁住真实存在的行记录。

Gap 间隙锁:锁住索引之间空隙,阻止插入;

Next‑Key 临键锁 = 记录锁 + 间隙锁,RR 下默认行锁。

间隙锁产生条件:RR 隔离级别,当前读,条件走索引,查询的数据不存在,锁住间隙防止插入,解决幻读。

8.死锁产生四个必要条件,线上如何排查 MySQL 死锁?

死锁 4 个必要条件(必须全部满足才会死锁)

  1. 互斥条件:资源同一时刻只能一个事务占用(行锁就是互斥)
  2. 不可剥夺:已经拿到锁的事务,别的事务不能强行抢走锁,只能自己释放
  3. 请求并保持:事务已经持有部分锁,同时还要去申请别的锁资源,不释放手上已有的
  4. 循环等待:两个 / 多个事务,互相持有对方想要的锁,形成环路等待。

记忆:互斥、不可剥夺、请求保持、循环等待,四个缺一不可;破坏任意一个就消除死锁。

MySQL 死锁排查

  1. 执行命令:show engine innodb status;
    输出结果里找到 LATEST DETECTED DEADLOCK 板块,里面记录最近一次死锁:两个事务分别执行什么 SQL、各自持有什么锁、等待什么锁。
  2. 看错误日志,也会打印死锁信息。
  3. 定位业务 SQL:调整加锁顺序,尽量统一获取锁的顺序,避免循环等待;减少大事务,事务尽快提交;RC 隔离级别消除间隙锁,降低死锁概率。

口述精简版:

死锁四条件:互斥、不可剥夺、请求并保持、循环等待。排查用show engine innodb status,查看 LATEST DETECTED DEADLOCK,拿到死锁两条事务 SQL;解决手段统一加锁顺序、缩小事务、可改为 RC 减少间隙锁。

9.explain 执行计划中 type 字段,从最优到最差排序,ALL 代表什么?

🔔完整 type 优先级(从最优 → 最差,面试必须背顺序

system > const > eq_ref > ref > range > index > ALL

简单解释关键几项:

  1. system:表只有一行数据,极少出现
  2. const:主键 / 唯一索引等值查询,最多匹配一行
  3. eq_ref:关联查询,主键、唯一索引匹配
  4. ref:普通索引等值匹配
  5. range:范围查询,> < between in
  6. index索引全扫描,扫全部索引叶子,不回表;比全表扫描 ALL 快,但数据量大依然慢
  7. ALL全表扫描,扫描聚簇索引全部数据行,性能最差

业务调优目标:尽量达到 range/ref,杜绝 index、ALL。

最后留个问题那么用到了索引就一定快吗?

相关推荐
番茄炒鸡蛋加糖1 天前
分布式 CAP、BASE 理论 & 中间件 CAP 取舍
分布式·中间件
Embedded-Xin2 天前
中间件学习-Iceoryx2零基础入门
学习·中间件
Embedded-Xin2 天前
中间件—zenoh零基础入门
linux·中间件·rust·机器人·自动驾驶·嵌入式
ThsPool7 天前
【ENVI二次开发学习整理 02】IDL语言基础与程序设计
学习·中间件
程序员良辰7 天前
【TongWeb7】启动接近两分钟问题排查
java·开发语言·中间件
哎呦,帅小伙哦9 天前
Nanomsg库AIO模块学习心得
中间件·nanomsg
kisloy12 天前
【爬虫入门第10讲】Scrapy 框架深度解析(一):五大组件与中间件
爬虫·scrapy·中间件
晴天1613 天前
AI应用开发(智能体-全栈开发工程师 岗位分析)-Day04
人工智能·中间件
fuquxiaoguang14 天前
MCP协议移交Linux基金会:AI智能体中间件标准定型,国产厂商迎“Kubernetes时刻”
linux·人工智能·中间件