MySQL 面试题集合 II - 读写分离,事物,MVCC,锁

Author: Xcourse   2023-Mar-17 17:24   Reads: 687

欢迎加入微信工作内部分享群,每天发布新的精选高薪工作。

官方邮箱:enquiry@xcourse.sg

微信分享群:@新加坡工作内部分享群

WhatsApp群:@Singapore Jobs & Internships

Telegram中文群:@新加坡工作内部分享群

Telegram英文群:@Singapore Jobs

------------------------------------------------------------------------------------------------------

 

(上一篇:MySQL 面试题集合 I - 索引, B+Tree , 切分 , 主从同步

 

22. 谈谈你对数据库读写分离的理解?

读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。

读写分离能提高性能的原因在于:

  1. 主从服务器负责各自的读和写,极大程度缓解了锁的争用;
  2. 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销;
  3. 增加冗余,提高可用性。

 

23. 请你描述下事务的特性?       

原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;

一致性:执行事务前后,数据库从一个一致性状态转换到另一个一致性状态。

隔离性:并发访问数据库时,一个用户的事物不被其他事务所干扰,各并发事务之间数据库是独立的;

持久性:一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库 发生故障也不应该对其有任何影响。

 

24. 谈谈你对事务隔离级别的理解?       

READ_UNCOMMITTED(未提交读): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读;

READ_COMMITTED(提交读): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生;

REPEATABLE_READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生;

SERIALIZABLE(串行化): 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

 

25. 解释下什么叫脏读、不可重复读和幻读?

脏读:

表示一个事务能够读取另一个事务中还未提交的数据。比如:某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。

不可重复读 :

是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两 次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不 可重复读。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果 只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题

不可重复读的重点是修改 :同样的条件 ,   你读取过的数据 ,   再次读取出来发现值不一样了

幻读:

指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。

幻读的重点在于新增或者删除:同样的条件 ,   第 1 次和第 2 次读出来的记录数不一样

 

26. MySQL 默认的隔离级别是什么?

MySQL默认采用的 REPEATABLE_READ隔离级别。

Oracle 默认采用的 READ_COMMITTED 隔离级别。

 

27. 谈谈你对MVCC 的了解?

数据库并发场景:

  1. 读-读:不存在任何问题,也不需要并发控制;
  2. 读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读;
  3. 写-写:有线程安全问题,可能会存在更新丢失问题。

多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。

MVCC 可以为数据库解决以下问题:

  1. 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能;
  2. 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题。

 

28. 说一下 MySQL 的行锁和表锁?

MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。

表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。

行级锁:开销大,加锁慢,会出现死锁。锁粒度小,发生锁冲突的概率小,并发度最高。

 

29. InnoDB 存储引擎的锁的算法有哪些?

Record lock:单个行记录上的锁;

Gap lock:间隙锁,锁定一个范围,不包括记录本身;

Next-key lock:record+gap 锁定一个范围,包含记录本身。

 

30. MySQL 问题排查都有哪些手段?

使用 show processlist 命令查看当前所有连接信息;

使用 Explain 命令查询 SQL 语句执行计划;

开启慢查询日志,查看慢查询的 SQL。

 

31. MySQL 数据库 CPU 飙升到 500% 的话他怎么处理?

当 CPU 飙升到 500% 时,先用操作系统命令 top 命令观察是不是 mysqld 占用导致的,如果不是,找出占用高的进程,并进行相关处理。

如果是 mysqld 造成的,通过 SHOW PROCESSLIST 查看正在运行的线程,是不是有消耗资源的 SQL 在运行,找出其中消耗高的 SQL,看看执行计划是否准确, index 是否缺失,或者是数据量太大造成。

然后 kill 掉这些线程(同时观察 CPU 使用率是否下降),等进行相应的调整(比如说加索引、改 SQL、改内存参数)之后,再重新跑这些 SQL。

若每个 SQL 消耗资源都不多,只是同一时间大量的 session 连进来导致 CPU 飙升,这种情况就需要分析为何连接数会激增,再做出相应的调整,比如说限制连接数等

 

32. MySQL的redo log,undo log,bin log都是干什么的

redo log是InnoDB引擎特有的,只记录该引擎中表的修改记录。binlog是MySQL的Server层实现的,会记录所有引擎对数据库的修改。

redo log是物理日志,记录的是在具体某个数据页上做了什么修改;binlog是逻辑日志,记录的是这个语句的原始逻辑。

redo log是循环写的,空间固定会用完;binlog是可以追加写入的,binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

以下是用户补充

  1. redolog记录修改内容(哪一页发生了什么变化),写于事务开始前,用于数据未落磁盘,但数据库挂了后的数据恢复
  2. binlog记录修改SQL,写于事务提交时,可用于读写分离
  3. undolog记录修改前记录,用于回滚和多版本并发控制

 

33. SQL 与 MySQL 有什么区别

SQL 和 MySQL 是 DBMS 中最令人困惑的两个术语,二者之间存在本质上的区别。

  1. SQL 是一种 结构化查询语言,用于在数据库上执行各种操作,但 MySQL 是一个 关系数据库管理系统(RDBMS),使用 SQL 执行所有数据库操作。
  2. SQL 用于访问,更新和操作数据库中的数据,用户使用时需要学习该语言,然后编写查询,而 MySQL 是一个软件,会为用户提供一个界面,只需单击一些按钮即可用于执行各种数据库操作。
  3. 由于 MySQL 是一个软件,所以它会定期获得各种更新,但在 SQL 中,命令总是相同的。

 

34. 添加索引的原则

索引虽好,但也不是无限制使用的,以下为添加索引时需要遵循的几项建议性原则:

  1. 在 查询中很少使用 或者参考的列不要创建索引。由于这些列很少使用到,增加索引反而会降低系统的维护速度和增大空间需求。
  2. 只有很少数据值的列 也不应该增加索引。由于这些列的取值很少,区分度太低,例如人事表中的性别,在查询时,需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
  3. 定义为 text、image 和 bit 数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
  4. 当 修改性能远远大于检索性能 时,不应该创建索引。这时因为,二者是相互矛盾的,当增加索引时,会提高检索性能,但是会降低修改性能。
  5. 定义有 外键 的数据列一定要创建索引。

 

35. 有哪些事务状态       

活跃状态:事务的第一个状态,任何正在执行的事务都处于此状态,所做的 更改 存储在 主内存的缓冲区 中。

部分提交状态:执行上次操作后,事务进入部分提交状态。之所以是部分提交,是因为所做的更改仍然在主内存的缓冲区中。

失败状态:如果某个检查在活动状态下失败,在活动状态或部分提交状态发生一些错误,并且事务无法进一步执行,则事务进入失败状态。

中止状态:如果任何事务已达到失败状态,则恢复管理器将数据库回滚到开始执行的原始状态。

提交状态:如果所有操作成功执行,则来自 部分提交状态 的事务进入提交状态。无法从此状态回滚,它是一个新的 一致状态。

 

36. 什么是死锁?如何解决死锁?

死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。

常见的解决死锁的方法

  1. 如果不同程序并发存取多个表,尽量约定 以相同的顺序访问表,可以大大降低死锁机会;
  2. 在同一个事务中,尽可能做到 一次锁定所需要的所有资源,减少死锁产生概率;
  3. 对于非常容易产生死锁的业务部分,可以尝试使用 升级锁定颗粒度,通过 表级锁 定来减少死锁产生的概率。

 

37. 什么是乐观锁和悲观锁?如何实现?

DBMS 中的 并发控制 的任务是确保在 多个事务同时存取数据库中同一数据 时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。这对于长事务来讲,可能会严重影响系统的并发处理能力。实现方式:使用数据库中的锁机制。

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。乐观锁适用于 读多写少 的应用场景,这样可以提高吞吐量。实现方式:一般会使用版本号机制或 CAS 算法实现。

 

38. 什么是超键?什么是主键?

超 键:在关系中,能唯一标识元组的属性集称为关系模式的超键。一个属性可以作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。

候选键:是最小超键,即没有冗余元素的超键。

主 键:数据库表中对储存数据对象予以 唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(NULL)。

外 键:在一个表中存在的另一个表的主键称此表的外键,外键可以有重复的, 可以是空值。外键是用来和其他表建立联系用的。

 

39. UNION 与 UNION ALL 的区别

UNION 用于把来自多个 SELECT 语句的结果组合到一个结果集合中,MySQL 会把结果集中 重复的记录删掉,而使用 UNION ALL,MySQL 会把所有的记录返回,且效率高于 UNION 。

 

40. DROP、DELETE 与 TRUNCATE 的区别

SQL 语句类型DDLDMLDDL
回滚不可回滚可回滚不可回滚
删除内容从数据库中 删除表,所有的数据行,索引和权限也会被删除表结构还在,删除表的 全部或者一部分数据行表结构还在,删除表中的 所有数据
删除速度删除速度最快删除速度慢,需要逐行删除删除速度快

因此,在不再需要一张表的时候,采用 DROP;在想删除部分数据行时候,用 DELETE;在保留表而删除所有数据的时候用 TRUNCATE。

 

41. 为什么要分库分表

数据库中的数据量不一定是可控的,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地数据操作,例如 增删改查的开销 也会越来越大;另外,若不进行分布式部署,而一台服务器的 资源 (CPU、磁盘、内存、IO 等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。所以,从 性能 和 可用性 角度考虑,会进行数据库拆分处理,具体地说,把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上,即 分库分表。

 

42. 分库分表存在哪些问题

事务问题:分库分表后,就成了分布式事务。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。

跨库跨表的 JOIN 问题:在执行了分库分表之后,难以避免会将原本逻辑关联性很强的数据划分到不同的表、不同的库上,这时,表的关联操作将受到限制,我们无法 JOIN 位于不同分库的表,也无法 JOIN 分表粒度不同的表,结果原本一次查询能够完成的业务,可能需要多次查询才能完成。

额外的数据管理负担和数据运算压力:额外的数据管理负担,最为常见的是数据的 定位问题 和数据的 增删改查 的重复执行问题,这些都可以通过应用程序来解决,但必然会引起额外的逻辑运算。

 

43. MySQL 读写分离的实现方案

MySQL 读写分离的实现方式主要基于 主从复制,通过 路由的方式 使应用对数据库的写请求只在 Master 上进行,读请求在 Slave 上进行。

具体地,有以下四种实现方案:

方案一:基于 MySQL proxy 代理

在应用和数据库之间增加 代理层,代理层接收应用对数据库的请求,根据不同请求类型(即是读 read 还是写 write)转发到不同的实例,在实现读写分离的同时可以实现负载均衡。MySQL 的代理最常见的是 mysql-proxy、cobar、mycat、Atlas 等。

方案二:基于应用内路由

基于应用内路由的方式即为在应用程序中实现,针对不同的请求类型去不同的实例执行 SQL。

具体实现可基于 spring 的 aop:用 aop 来拦截 spring 项目的 dao 层方法,根据方法名称就可以判断要执行的类型,进而动态切换主从数据源。

方案三:基于 MySQL-Connector-Java 的 JDBC 驱动方式

Java 程序通过在连接 MySQL 的 JDBC 中配置主库与从库等地址,JDBC 会自动将读请求发送给从库,将写请求发送给主库,此外, MySQL 的 JDBC 驱动还能够实现多个从库的负载均衡。

方案四:基于 sharding-jdbc 的方式

sharding-sphere 是强大的读写分离、分表分库中间件,sharding-jdbc 是 sharding-sphere 的核心模块。

 


Tags: interview mysql backend

Topics: 面经