Skip to content

MySQL


1. 事务的ACID特性是什么?如何保证的?

  • 原子性 (Atomicity):事务是最小执行单元,全部成功或全部失败。通过Undo Log实现回滚。
  • 一致性 (Consistency):事务前后数据库保持合法状态。由应用层和数据库约束共同保证。
  • 隔离性 (Isolation):事务间操作相互隔离。通过锁和MVCC机制实现。
  • 持久性 (Durability):事务提交后数据永久保存。通过Redo Log和刷盘策略保证。

2. MySQL的隔离级别有哪些?分别解决什么问题?

  • 读未提交 (RU):可能脏读、不可重复读、幻读。
  • 读已提交 (RC):解决脏读,但可能出现不可重复读和幻读(默认隔离级别)。
  • 可重复读 (RR):解决脏读、不可重复读(MySQL默认级别,通过MVCC+Next-Key Locks避免幻读)。
  • 串行化 (Serializable):完全隔离,性能最低。

3. 什么是MVCC?如何实现的?

  • MVCC (多版本并发控制):通过快照读实现非阻塞读,解决读写冲突。
  • 实现机制
  • 每行数据包含隐藏字段DB_TRX_ID(事务ID)和DB_ROLL_PTR(回滚指针)。
  • 通过Undo Log构建版本链,结合ReadView判断数据可见性。
  • 只在RCRR隔离级别下生效。

4. InnoDB的索引结构是什么?B+树相比B树的优势?

  • B+树索引:非叶子节点只存键值,叶子节点存储数据(聚集索引存整行,二级索引存主键)。
  • 优势
  • 叶子节点形成有序链表,范围查询高效。
  • 非叶子节点存储更多键,树高更低,减少IO次数。
  • 数据只存在叶子节点,查询稳定性更高。

5. 死锁是如何产生的?如何检测和避免?

  • 产生条件:互斥、请求与保持、不可剥夺、循环等待。
  • 检测:通过等待图 (Wait-for Graph)检测循环依赖,触发死锁回滚。
  • 避免方案
  • 事务按固定顺序访问资源。
  • 降低事务粒度,减少锁竞争。
  • 设置合理的事务超时时间(innodb_lock_wait_timeout)。
  • 使用SELECT ... FOR UPDATE NOWAIT(MySQL 8.0+)。

6. 如何优化慢查询?

  1. 定位慢SQL:开启slow_query_log,分析慢日志。
  2. Explain分析:关注type(扫描方式)、key(使用索引)、rows(扫描行数)、Extra(是否Using filesort/Using temporary)。
  3. 优化方向
  4. 添加缺失索引,避免全表扫描。
  5. 优化SQL写法(如拆分复杂查询、避免SELECT *)。
  6. 使用覆盖索引,减少回表操作。
  7. 调整表结构(如范式化/反范式化)。

7. 主从复制原理是什么?延迟如何解决?

  • 原理:主库通过Binlog记录变更,从库通过I/O线程拉取日志,SQL线程重放。
  • 延迟解决
  • 并行复制(MTS,基于库/组提交/事务粒度)。
  • 调整sync_binloginnodb_flush_log_at_trx_commit参数平衡安全与性能。
  • 使用半同步复制(semisync)确保主从数据一致性。

8. 分库分表的常见方案及优缺点?

  • 垂直拆分:按业务拆分(如订单库、用户库)。
  • 优点:解耦业务,降低单库压力。
  • 缺点:无法解决单表数据量过大的问题。
  • 水平拆分:按规则分散数据(如按ID取模、按时间范围)。
  • 优点:解决单表数据膨胀问题。
  • 缺点:跨分片查询复杂,事务管理困难。
  • 代理层 vs 客户端分片:ShardingSphere、MyCAT等工具实现。

9. Explain中的Using index conditionUsing index有何区别?

  • Using index:仅用索引即可返回所需数据(覆盖索引)。
  • Using index condition:使用索引条件下推(ICP),在存储引擎层过滤数据,减少回表次数。

10. 什么是覆盖索引?举例说明。

  • 定义:查询的字段全部被索引覆盖,无需回表。
  • 示例
-- 创建索引 (age, name)
CREATE INDEX idx_age_name ON user(age, name);

-- 查询命中覆盖索引
SELECT age, name FROM user WHERE age \> 20;

聚集索引 vs 非聚集索引详解


1. 核心概念

聚集索引 (Clustered Index)

  • 数据即索引:索引的叶子节点直接存储完整行数据
  • 物理有序:表中的数据行按聚集索引的键值顺序存储(类似电话簿按姓名排序)
  • 唯一性:一张表有且仅有一个聚集索引(InnoDB强制要求)

非聚集索引 (Non-Clustered Index)

  • 索引与数据分离:叶子节点存储主键值(InnoDB中)或行指针(MyISAM中)
  • 逻辑有序:索引本身有序,但数据行物理存储无序
  • 可多个共存:一张表可以创建多个非聚集索引(二级索引)

2. 存储结构对比

InnoDB引擎实现

特征 聚集索引 非聚集索引
叶子节点内容 存储完整数据行 存储主键值
B+树结构 主键构建的B+树即数据文件 独立B+树结构
查找流程 直接返回数据 先查主键,再通过主键查聚集索引(回表)

示例结构图


3. 关键差异分析

对比维度 聚集索引 非聚集索引
数据存储方式 数据按索引顺序物理存储 索引与数据物理分离
查询速度 主键查询极快(直接定位数据) 需要二次查找(回表)
插入效率 顺序插入高效,随机插入可能产生页分裂 插入只需更新索引树
空间占用 无额外存储空间 需要额外存储索引结构
更新代价 主键修改代价高(需移动数据行) 只需更新索引树

4. 典型场景示例

场景1:主键查询

SELECT * FROM users WHERE id = 5; 

执行流程: 聚集索引:直接通过B+树定位到数据行 非聚集索引:不适用(主键本身就是聚集索引)

场景2:二级索引查询

-- 假设在email字段上创建了非聚集索引

SELECT * FROM users WHERE email = 'user@example.com';

执行流程: 在email索引树中找到对应记录,获取主键id 用主键id到聚集索引树中查找完整数据(回表)

  1. 常见误区 误区1:"主键一定是聚集索引" 事实:在InnoDB中主键自动成为聚集索引,但若未定义主键: 选择第一个UNIQUE且非空的字段 否则隐式创建6字节的DB_ROW_ID作为聚集索引 误区2:"非聚集索引查询性能差" 优化方案: 通过覆盖索引避免回表 使用索引条件下推(ICP,Index Condition Pushdown)