首页 > C++ MySql 常考面试题总结
头像
英杰速演
发布于 昨天 11:27 河北
+ 关注

C++ MySql 常考面试题总结

1. 事务有哪几种类型,它们之间有什么区别?

事务按ACID特性和实现方式,主要分为以下几类:

  • 扁平事务(Flat Transaction):最常见的事务类型,由一组操作组成,要么全部提交,要么全部回滚,无嵌套结构。
  • 嵌套事务(Nested Transaction):允许在事务内部再开启子事务,子事务可独立提交或回滚,但父事务提交后子事务才真正生效;MySQL InnoDB不原生支持嵌套事务,可通过SAVEPOINT模拟。
  • 分布式事务(Distributed Transaction):跨多个数据库或服务的事务,需通过两阶段提交(2PC)、三阶段提交(3PC)等协议保证一致性,常见于微服务架构。
  • 长事务(Long Transaction):执行时间较长的事务,易导致锁竞争和性能问题,需避免在业务中使用。

2. MySQL的ACID特性分别是怎么实现的?

  • 原子性(Atomicity):通过Undo Log实现,事务执行过程中产生的修改操作会记录到Undo Log,若事务回滚,可通过Undo Log撤销所有操作。
  • 一致性(Consistency):由原子性、隔离性和持久性共同保证,同时依赖数据库约束(如主键、外键、唯一索引)和应用层逻辑。
  • 隔离性(Isolation):通过锁机制和MVCC(多版本并发控制)实现,不同隔离级别通过锁和MVCC的组合,避免并发事务间的相互干扰。
  • 持久性(Durability):通过Redo Log实现,事务提交前,修改操作会先写入Redo Log并持久化到磁盘,即使数据库崩溃,重启后可通过Redo Log恢复数据。

3. 谈谈MySQL的事务隔离级别

MySQL InnoDB支持四种隔离级别,从低到高依次为:

  1. 读未提交(READ UNCOMMITTED):事务可读取其他事务未提交的数据,会导致脏读、不可重复读、幻读。
  2. 读已提交(READ COMMITTED):事务只能读取其他事务已提交的数据,可避免脏读,但仍存在不可重复读、幻读。
  3. 可重复读(REPEATABLE READ):MySQL InnoDB默认隔离级别,事务执行期间多次读取同一数据的结果一致,可避免脏读、不可重复读,通过Next-Key Lock避免幻读。
  4. 串行化(SERIALIZABLE):强制事务串行执行,所有读操作加共享锁,写操作加排他锁,可避免所有并发问题,但性能极低。

4. MySQL的事务隔离级别是怎么实现的?

  • 读未提交:直接读取最新数据,无锁和MVCC,性能最高但隔离性最差。
  • 读已提交:通过MVCC实现,每次读取时生成最新的Read View,仅能看到已提交的数据,避免脏读。
  • 可重复读:通过MVCC实现,事务开始时生成唯一的Read View,整个事务期间使用该Read View,保证同一事务内多次读取结果一致;同时通过Next-Key Lock避免幻读。
  • 串行化:对所有读操作加共享锁,写操作加排他锁,事务间串行执行,无并发但完全隔离。

5. 事务可以嵌套吗?

MySQL InnoDB不原生支持嵌套事务,但可通过SAVEPOINT实现类似效果:

  • 执行SAVEPOINT sp1设置保存点,后续可通过ROLLBACK TO sp1回滚到该保存点,仅撤销保存点之后的操作,不影响保存点之前的操作。
  • 注意:SAVEPOINT并非真正的嵌套事务,父事务提交后子事务才生效,父事务回滚子事务也会全部回滚。

6. 如何实现可重复读?

InnoDB通过MVCC(多版本并发控制)实现可重复读:

  1. 事务开始时,生成唯一的Read View,记录当前活跃事务的ID和最小未提交事务ID。
  2. 读取数据时,根据Read View判断数据版本的可见性,仅能看到事务开始前已提交的数据和本事务内修改的数据。
  3. 同一事务内多次读取同一数据时,始终使用同一个Read View,保证读取结果一致,避免不可重复读。

7. 如何解决幻读问题?

幻读是指同一事务内,两次查询的结果集行数不同(如第一次查询10条,第二次查询12条,因其他事务插入了新数据)。InnoDB通过Next-Key Lock(间隙锁+行锁)解决幻读:

  • 对查询范围内的所有行加行锁,同时对行之间的间隙加间隙锁,阻止其他事务在间隙中插入新数据,保证查询结果集行数一致。
  • 注意:仅在可重复读及以上隔离级别下,Next-Key Lock才生效,可避免幻读。

8. MySQL事务如何回滚?

  • 显式回滚:执行ROLLBACK语句,撤销当前事务的所有操作,释放锁和Undo Log。
  • 隐式回滚:事务执行过程中发生错误(如死锁、约束冲突)或数据库崩溃,MySQL会自动回滚事务,通过Undo Log恢复数据。
  • 核心依赖:Undo Log记录了事务执行前的数据版本,回滚时通过Undo Log将数据恢复到事务开始前的状态。

9. 了解数据库的锁吗?

数据库锁用于控制并发访问,保证数据一致性,主要分为以下几类:

  • 按粒度分:行级锁(InnoDB)、表级锁(MyISAM)、页级锁(较少用)。
  • 按性质分:共享锁(S锁,读锁,允许多个事务同时读,不允许写)、排他锁(X锁,写锁,独占资源,不允许其他事务读写)。
  • 按实现分:意向锁(表级锁,表明事务即将对表内行加锁,提升锁检测效率)、间隙锁(锁定行之间的间隙,防止插入)、Next-Key Lock(行锁+间隙锁,避免幻读)。

10. 介绍一下间隙锁,InnoDB中行级锁是怎么实现的?

  • 间隙锁(Gap Lock):锁定索引记录之间的间隙,不锁定具体行,用于防止其他事务在间隙中插入新数据,避免幻读。
  • 行级锁实现:InnoDB基于索引实现行级锁,若查询未命中索引,会退化为表级锁;行级锁分为共享锁和排他锁,通过锁的兼容性控制并发访问。
  • Next-Key Lock:行锁+间隙锁的组合,锁定索引记录和其前后的间隙,是InnoDB在可重复读隔离级别下避免幻读的核心机制。

11. 数据库在什么情况下会发生死锁?

死锁是指两个或多个事务互相持有对方所需的锁,且均不释放已持有的锁,导致所有事务永久阻塞。常见场景:

  1. 事务A持有行1的X锁,请求行2的X锁;事务B持有行2的X锁,请求行1的X锁,形成循环等待。
  2. 多个事务按不同顺序更新同一批数据,导致锁请求顺序冲突。
  3. 长事务持有锁不释放,其他事务请求锁时形成死锁。

12. 说说数据库死锁的解决办法

  • 预防死锁:按固定顺序访问数据(如按主键升序更新),避免循环等待。避免长事务,及时释放锁。降低隔离级别(如从可重复读改为读已提交),减少锁竞争。
  • 检测与解除:MySQL通过死锁检测机制(如等待图)定期检测死锁,检测到后主动回滚代价较小的事务(如执行时间短的事务)。设置锁等待超时时间(innodb_lock_wait_timeout),超时后自动回滚事务。

13. 说一说你对数据库优化的理解

数据库优化是一个系统性工程,核心目标是提升查询效率、降低资源消耗、保证数据一致性,主要分为四个层面:

  1. SQL与索引优化:优化慢查询、添加合适的索引、避免全表扫描。
  2. 表结构优化:合理设计表结构(如拆分大表、避免冗余字段)、选择合适的数据类型(如用INT代替VARCHAR存储数字)。
  3. 数据库配置优化:调整内存参数(如innodb_buffer_pool_size)、日志参数(如Redo Log大小)、并发参数(如max_connections)。
  4. 架构优化:读写分离、分库分表、缓存层(如Redis)、数据库集群(如主从复制、分片)。

14. 该如何优化MySQL的查询?

  • 优化SQL语句:避免SELECT *,只查询需要的字段,减少数据传输和内存消耗。避免在WHERE子句中对索引列使用函数或表达式,导致索引失效。拆分复杂查询,用简单查询替代子查询和多表连接。
  • 添加合适的索引:对WHERE、JOIN、ORDER BY子句中的列添加索引,优先选择选择性高的列。避免创建过多索引,索引会降低写入性能。
  • 使用EXPLAIN分析执行计划:查看查询是否命中索引、是否全表扫描、是否有临时表和文件排序,针对性优化。

15. 怎样插入数据才能更高效?

  • 批量插入:使用INSERT INTO ... VALUES (...), (...)批量插入,减少事务提交次数和日志写入开销。
  • 关闭自动提交:批量插入前关闭自动提交(SET autocommit=0),插入完成后统一提交,避免频繁事务提交。
  • 禁用索引和约束:批量插入前禁用索引和外键约束,插入完成后重建索引,提升插入速度(注意:仅适用于离线批量插入)。
  • 调整数据库参数:增大innodb_buffer_pool_size、innodb_log_file_size,提升写入性能。

16. 表中包含几千万条数据该怎么办?

  • 分表分库:水平分表:按主键或时间范围拆分表(如按用户ID哈希分表、按月份分表),降低单表数据量。垂直分表:将大表按字段拆分(如将常用字段和不常用字段拆分到不同表),减少单表宽度。分库:将不同业务模块的数据拆分到不同数据库,提升并发处理能力。
  • 读写分离:主库负责写入,从库负责读取,分担读压力。
  • 缓存层:用Redis缓存热点数据,减少数据库查询次数。
  • 归档历史数据:将不常用的历史数据归档到冷存储,避免影响热数据查询性能。

17. MySQL的慢查询优化有了解吗?

  • 开启慢查询日志:设置slow_query_log=1,记录执行时间超过long_query_time(默认10秒)的查询,定位慢查询。
  • 分析慢查询日志:用mysqldumpslow、pt-query-digest等工具分析慢查询,找出高频慢查询和性能瓶颈。
  • 优化慢查询:对慢查询添加索引,避免全表扫描。优化SQL语句,减少子查询和多表连接。调整数据库参数,提升查询性能(如增大join_buffer_size)。

18. 说一说你对explain的了解

EXPLAIN是MySQL的执行计划分析工具,用于查看查询语句的执行过程,核心字段含义:

  • id:查询的执行顺序,id越大优先级越高。
  • select_type:查询类型(如SIMPLE、SUBQUERY、DERIVED)。
  • table:查询涉及的表。
  • type:连接类型(如ALL、index、range、ref、eq_ref、const),从差到好,ALL表示全表扫描,const表示主键或唯一索引查询。
  • key:实际使用的索引,若为NULL表示未命中索引。
  • rows:MySQL预估需要扫描的行数,行数越少性能越好。
  • Extra:额外信息(如Using index、Using where、Using filesort、Using temporary),Using filesort和Using temporary会严重影响性能。

19. 什么是MVCC?它的作用是什么?

MVCC(多版本并发控制)是InnoDB实现隔离性的核心机制,通过保存数据的历史版本,让读操作不加锁,同时保证事务隔离。

  • 核心原理:每行数据隐藏两个字段——DB_TRX_ID(最后修改该数据的事务ID)和DB_ROLL_PTR(指向Undo Log中历史版本的指针)。
  • 作用:实现可重复读和读已提交隔离级别,避免脏读、不可重复读。提升并发性能,读操作不加锁,写操作仅锁定必要的行。

20. 什么是索引?索引的类型有哪些?

索引是一种数据结构,用于快速定位数据,提升查询效率。常见类型:

  • B+树索引:InnoDB默认索引类型,支持范围查询和排序,是最常用的索引。
  • 哈希索引:基于哈希表实现,仅支持等值查询,不支持范围查询,InnoDB的自适应哈希索引属于此类。
  • 全文索引:用于全文检索,支持对文本内容的关键词查询。
  • 空间索引:用于地理空间数据(如经纬度)的查询。

21. 索引为什么能提升查询效率?

  • 索引将无序的数据变为有序的B+树结构,查询时可通过二分查找快速定位数据,避免全表扫描。
  • 覆盖索引(查询的字段都在索引中)可直接从索引中获取数据,无需回表查询,进一步提升性能。

22. 什么是覆盖索引?

覆盖索引是指查询的所有字段都包含在索引中,MySQL可直接从索引中获取数据,无需回表查询主键索引,大幅提升查询效率。

  • 示例:SELECT name FROM user WHERE age=18,若(age, name)是联合索引,该查询可直接从索引中获取name,无需回表。

23. 什么是联合索引?联合索引的最左前缀原则是什么?

联合索引是指对多个列创建的索引,如(a, b, c)。最左前缀原则是指:

  • 查询时,只有从索引的最左列开始连续使用索引列,才能命中索引。
  • 示例:联合索引(a, b, c),查询WHERE a=1 AND b=2可命中索引,查询WHERE b=2无法命中索引。

24. 什么是索引失效?常见的索引失效场景有哪些?

索引失效是指查询无法使用已创建的索引,导致全表扫描。常见场景:

  • 在WHERE子句中对索引列使用函数或表达式(如WHERE YEAR(create_time)=2024)。
  • 违反最左前缀原则(如联合索引(a, b),查询WHERE b=1)。
  • 使用OR连接条件,其中一个条件未命中索引。
  • 数据量过小,MySQL认为全表扫描比索引查询更快。

25. 什么是主从复制?主从复制的原理是什么?

主从复制是指将主库的数据同步到从库,实现读写分离和高可用。

  • 原理:主库将数据修改操作记录到Binlog。从库的I/O线程读取主库的Binlog,写入到Relay Log。从库的SQL线程读取Relay Log,执行其中的操作,同步数据到从库。

26. 主从复制的延迟问题如何解决?

  • 优化主库写入性能:减少主库的写入压力,避免频繁的大事务。
  • 调整从库参数:增大innodb_buffer_pool_size、slave_parallel_workers,提升从库的执行效率。
  • 使用半同步复制:主库等待至少一个从库确认接收Binlog后再提交,减少数据丢失风险,但会增加延迟。
  • 分库分表:拆分大表,减少单表数据量,提升复制速度。

27. 什么是分库分表?分库分表的策略有哪些?

分库分表是指将一个大数据库或大表拆分为多个小数据库或小表,提升并发处理能力和查询性能。

  • 水平分表:按主键或时间范围拆分表(如按用户ID哈希分表、按月份分表)。
  • 垂直分表:将大表按字段拆分(如将常用字段和不常用字段拆分到不同表)。
  • 分库:将不同业务模块的数据拆分到不同数据库,提升并发处理能力。

28. 什么是数据库的三大范式?

  • 第一范式(1NF):列不可再分,保证原子性。
  • 第二范式(2NF):在1NF的基础上,非主键列完全依赖于主键,而非主键的一部分。
  • 第三范式(3NF):在2NF的基础上,非主键列不依赖于其他非主键列,避免传递依赖。
  • 注意:实际开发中可根据业务需求适当反范式,如添加冗余字段提升查询性能。

29. 什么是视图?视图的作用是什么?

视图是一个虚拟表,基于一个或多个表的查询结果创建,本身不存储数据。

  • 作用:简化复杂查询,将多表连接和子查询封装为视图。控制数据访问权限,只允许用户访问视图中的数据,而非原始表。保护敏感数据,隐藏原始表的结构和字段。

30. 什么是存储过程?存储过程的优缺点是什么?

存储过程是一组预编译的SQL语句,存储在数据库中,可通过调用执行。

  • 优点:减少网络传输,一次调用即可执行多条SQL语句。提升性能,预编译的SQL语句可重复使用。封装业务逻辑,保证数据一致性。
  • 缺点:可移植性差,不同数据库的存储过程语法不同。调试和维护困难,业务逻辑分散在数据库中。过度使用会导致数据库压力过大。

全部评论

(7) 回帖
加载中...
话题 回帖

近期热帖

热门推荐