LOADING

加载过慢请开启缓存 浏览器默认开启

MySQL

2025/9/13 知识

MySQL

索引

什么是索引?

  • 索引是MySQL优化查询速度,帮助搜索引擎快速获取数据的数据结构

常用的索引类型有哪些?

  • 主键索引:唯一标识记录,默认自增且非空,一张表只能有一个主键
  • 唯一索引:索引列值唯一,如用户手机号索引
  • 普通索引:无唯一性要求,最常用,如商品名称索引
  • 联合索引:多列组合的索引(如用户名+手机号),需遵循“最左前缀原则”

什么情况下索引会失效?

  • 索引列用了函数/计算,就会导致索引失效
  • 索引列用了不等于,(!=,<>)
  • 联合索引不满足“最左前缀”
  • 对索引使用左或左右模糊匹配

MySQL实现索引的数据结构是什么?为什么?

  • InnoDB是MySQL默认的存储引擎,它是采用B+树作为索引的数据结构

  • B+树是一种多叉树,并且非叶子节点不存放实际的记录数据,仅放索引,因此查询底层节点的磁盘I/O次数会更少

  • B+树有大量的冗余节点,使得B+树在插入,删除的效率都更高

什么是回表查询?如何避免回表?

  • 当查询语句依赖了非聚簇索引(如普通索引,唯一索引,联合索引),但所需的字段超过了非聚簇索引叶子节点存储的内容,就会根据查询条件找到索引项,获取主键值,再根据聚簇索引找到对应的叶子节点
  • 要避免回表就需要让查询的所有字段,都能从非聚簇索引中直接获取,无需查聚簇索引

事务

什么是事务?作用是什么?

  • 事务时数据库种一组不可分割的SQL执行单元,要么全部成功(提交),要么全部失败(回滚)
  • 核心作用是为了保证多部操作的数据一致性

事务有哪些特性?(事务的ACID特性是什么?)

  • 原子性:事务是不可分割的最小单元,操作要么全成,要么全回滚 是通过undo log(回滚日志)实现
  • 隔离性:多个事务并发执行时,一个事务的操作不会被其他事务干扰,通过MVCC(多版本并发控制)或锁机制来保证
  • 持久性:事务提交后,修改会永久保存到磁盘,即使数据库崩溃,也不会丢失,通过redo log(重做日志)来保证
  • 一致性:事务执行前后,数据库保证一致性状态,由原子性+隔离性+持久性共同保证

并行事务会引发什么问题?

  • 脏读:一个事务读到了另一个事务未提交的修改(未提交就有随时回滚的风险)
  • 不可重复读:同一事务内,多次读取同一数据,返回的数据结果不一样(在一个事务两次读取的间隙,另一事务完成提交,修改了这个数据)
  • 幻读:同一事务内,多次执行相同查询,返回的数据行数不一致(在一个事务两次读取的间隙,另一事务完成提交,增加了一行数据)

MySQL的四大隔离级别分别是什么?它们对应的并发问题解决能力如何?

  • 读未提交:允许读未提交的数据;无法解决任何并发问题

  • 读已提交:允许未提交数据;只能解决‘脏读’,仍有‘不可重复读’‘幻读’

  • 可重复的:同一事务内部数据一致;解决‘脏读’‘不可重复读’一定程度上避免了‘幻读’(一般就在这一隔离级别)

  • 串行化:事务串行执行,完全不并发;解决所有并发问题

InnoDB 中保证事务ACID特性的核心日志有哪些?分别作用是什么?

  • redo log(重做日志):保证事务持久性,记录事务对数据的修改,事务提交前先写redo log,即使数据库崩溃,重启后可通过redo log恢复已提交的数据
  • undo log(回滚日志):保证事务原子性和隔离性,记录事务修改前的数据,用于数据回滚,也可用于数据快照(MVCC)
  • binlog(二进制日志):记录所有数据修改操作,主要用于主从复制和数据恢复

InnoDB 的MVCC(多版本并发控制器)和事务隔离级别的关系?

  • MVCC是实现隔离性的核心,通过为数据生成“多版本快照”,让不同事务在并发时看到不同版本的数据,避免锁竞争
    1. 读可提交:每次查询都生成新的快照,只能看到已提交的最新数据
    2. 可重复读:事务一开始,生成一次快照,整个事务用这一个快照

MySQL常见的锁类型?按粒度分

  • 全局锁:锁住整个数据库,使数据库处于只读状态

  • 表级锁:锁定整张表,粒度大,开销小,加锁快,并发度低

    1. 表共享读锁:允许其他事务读,禁止写
    2. 表独占写锁:允许其他事务读和写
    3. 意向锁:避免表锁和行锁冲突
  • 行级锁:锁定单行数据,粒度小,开销大,加锁慢,并发度高

    1. 共享锁:事务读数据时加锁,其他事务可以加共享锁,不可以加排他锁
    2. 排他锁:事务写数据时加锁,其他事务不可加任何锁
  • 页级锁:粒度介于表锁和行锁之间,MySQL极少使用

InnoDB行锁是基于什么实现的?为什么会出现幻读?

  • 是基于聚簇索引(主键索引)实现的,若未走主键索引,会升级为表锁
  • 行锁仅锁定“已存在的行”,无法阻止其他事务“插入新行”

什么是乐观锁和悲观锁?MySQL如何实现的?

  • 悲观锁:假设并发冲突会发生,直接加锁阻塞其他事务,行锁,表锁都是悲观锁
  • 乐观锁:假设并发冲突不会发生,不加锁,仅在提交时校验数据是否被修改,一般实现是在表中加version字段

隔离级别与锁的关系?

  • 读未提交:无锁
  • 读已提交:行锁+MVCC
  • 可重复读:行锁+MVCC+间隙锁
  • 串行化:读加S锁,写加X锁,完全串行执行

什么是间隙锁?作用是什么?

  • 间隙锁是对范围查询时,除了锁定范围内的行,还会锁定范围内不存在的间隙
  • 防止其他事务在间隙中插入新行

MySQL的死锁什么时候会发生?怎么避免?

  • 满足死锁的四个条件:互斥、占有且等待、不可强占用、循环等待
  • 设置事务等待锁的超时时间、开启主动死锁检测