MySQL 面试题
ACID
- 原子性, 日志实现 (A)
- 持久性, 日志实现 (D)
- 隔离性, 并发控制, 日志 + 锁实现 + MVCC 优化 (I)
- 一致性, 数据库约束实现 (C)
WAL 机制
- 先顺序写入日志
- 异步应用到数据文件
- COMMIT 时, 日志 fsync 确保持久
- 回滚时, 逆向应用日志
- 使用循环缓冲区或 LSM-Tree存储
执行计划
文件排序
- 排序字段未索引, 或索引类型错误, 会导致文件排序
- 内存排序, 内存不足时, 磁盘排序
索引
为什么数据库索引用 B+ 树
- 磁盘读写代价高, 所以要尽量减少读写次数, B/B+ 树的高度低, 读写次数少
- B+ 树的非叶子节点只存储索引, 不存储数据, 所以分叉更多 (节点最大空间为磁盘块大小), 高度更低
- B+ 树的叶子节点是一个有序链表, 方便范围查询与遍历
- B+ 树的索引部分小, MySQL 易于缓存
聚簇索引和非聚簇索引
- 聚簇索引: 数据和索引存储在一起, 每个表只能有一个聚簇索引 (InnoDB 引擎默认)
- 非聚簇索引: 数据和索引存储分离, 每个表可以有多个非聚簇索引 (会出现回表查询)
联合索引的最左前缀原则
- 联合索引的最左前缀原则: 联合索引的字段, 必须从左到右连续使用, 否则索引失效
组合索引
- 就是先按第一个字段排序, 再按第二个字段排序, 以此类推
经典索引慢查询
- 索引命中, 但需要回表查询 (尤其是低选择项, 索引本来就意义不大)
- 给索引项加没必要的函数, 会导致索引失效
- 索引类型不一致, 隐式类型转换, 导致索引失效
锁
- 行锁, 表锁
- 行锁: 锁定行, 其他事务可以读取, 但不能修改
- 表锁: 锁定表, 其他事务不能读取, 也不能修改
事务隔离级别
RU (读未提交)
- 字面意思
RC (读已提交)
- 解决了脏读问题
- 利用 MVCC 每个语句读取时, 只读取有版本号的数据, 避免读取到未提交的数据
UPDATA匹配未命中索引时, 会全表扫描, 但发现行被锁, 不会阻塞等待锁释放, 而是读取 Undo Log 中的旧值 (DELETE反之)
RR (可重复读)
- 解决了不可重复读问题
- 但是幻读问题还没有解决
SI (串行化)
- 解决了幻读问题
- 但是性能很差, 不建议使用
MVCC
两阶段提交(2PC)的原理?有什么问题? 三阶段提交(3PC)如何改进2PC?
分库分表
主从复制
- 主库: 写操作, 并通过二进制日志 (binlog) 同步到从库
- 从库: 读操作, 订阅主库的 binlog, 并实时应用到本地数据库, 有时级联复制, 缓解主库 binlog 压力
主从复制的一致性
- 从库的复制是异步的, 存在延时
- 短时不一致看业务场景, 通常可以接受
- 严格一致时, 将主库的写操作顺序应用到从库后返回 (同步)
- 选择性读主, 插入时将该 key 缓存在 redis, 设置过期时间 (预期的同步时间), 读取时先看 redis 是否近期写, 如果是, 主库读取, 否则从库读取