MySQL数据库常见面试题总结

1、数据库的常用范式:

  • 第一范式(1NF):指表的列不可再分,数据库中表的每一列都是不可分割的基本数据项,同一列中不能有多个值;
  • 第二范式(2NF):在 1NF 的基础上,还包含两部分的内容:一是表必须有一个主键;二是表中非主键列必须完全依赖于主键,不能只依赖于主键的一部分;
  • 第三范式(3NF):在 2NF 的基础上,消除非主键列对主键的传递依赖,非主键列必须直接依赖于主键。
  • BC范式(BCNF):在 3NF 的基础上,消除主属性对于码部分的传递依赖

 

2、SQL语句的执行过程:

2.1、客户端的数据库驱动与数据库连接池:

(1)客户端与数据库进行通信前,通过数据库驱动与MySQL建立连接,建立完成之后,就发送SQL语句

(2)为了减少频繁创建和销毁连接造成系统性能的下降,通过数据库连接池维护一定数量的连接线程,当需要进行连接时,就直接从连接池中获取,使用完毕之后,再归还给连接池。常见的数据库连接池有 Druid、C3P0、DBCP

2.2、MySQL架构的Server层的执行过程:

(1)连接器:主要负责跟客户端建立连接、获取权限、维持和管理连接

(2)查询缓存:优先在缓存中进行查询,如果查到了则直接返回,如果缓存中查询不到,在去数据库中查询。

MySQL缓存是默认关闭的,也就是说不推荐使用缓存,并且在MySQL8.0 版本已经将查询缓存的整块功能删掉了。这主要是它的使用场景限制造成的:

  • 先说下缓存中数据存储格式:key(sql语句)- value(数据值),所以如果SQL语句(key)只要存在一点不同之处就会直接进行数据库查询了;
  • 由于表中的数据不是一成不变的,大多数是经常变化的,而当数据库中的数据变化了,那么相应的与此表相关的缓存数据就需要移除掉;

(3)解析器/分析器:分析器的工作主要是对要执行的SQL语句进行词法解析、语法解析,最终得到抽象语法树,然后再使用预处理器对抽象语法树进行语义校验,判断抽象语法树中的表是否存在,如果存在的话,在接着判断select投影列字段是否在表中存在等。

(4)优化器:主要将SQL经过词法解析、语法解析后得到的语法树,通过数据字典和统计信息的内容,再经过一系列运算 ,最终得出一个执行计划,包括选择使用哪个索引

在分析是否走索引查询时,是通过进行动态数据采样统计分析出来;只要是统计分析出来的,那就可能会存在分析错误的情况,所以在SQL执行不走索引时,也要考虑到这方面的因素

(5)执行器:根据一系列的执行计划去调用存储引擎提供的API接口去调用操作数据,完成SQL的执行。

2.3、Innodb存储引擎的执行过程:

  • (1)首先MySQL执行器根据 执行计划 调用存储引擎的API查询数据
  • (2)存储引擎先从缓存池buffer pool中查询数据,如果没有就会去磁盘中查询,如果查询到了就将其放到缓存池中
  • (3)在数据加载到 Buffer Pool 的同时,会将这条数据的原始记录保存到 undo 日志文件中
  • (4)innodb 会在 Buffer Pool 中执行更新操作
  • (5)更新后的数据会记录在 redo log buffer 中
  • (6)提交事务在提交的同时会做以下三件事
  • (7)(第一件事)将redo log buffer中的数据刷入到redo log文件中
  • (8)(第二件事)将本次操作记录写入到 bin log文件中
  • (9)(第三件事)将bin log文件名字和更新内容在 bin log 中的位置记录到redo log中,同时在 redo log 最后添加 commit 标记
  • (10)使用一个后台线程,它会在某个时机将我们Buffer Pool中的更新后的数据刷到 MySQL 数据库中,这样就将内存和数据库的数据保持统一了

 详细内容请阅读这篇文章:https://blog.csdn.net/a745233700/article/details/113927318

 

3、常用的存储引擎?InnoDB与MyISAM的区别?

存储引擎是对底层物理数据执行实际操作的组件,为Server服务层提供各种操作数据的API。常用的存储引擎有InnoDB、MyISAM、Memory。这里我们主要介绍InnoDB 与 MyISAM 的区别:

(1)事务:MyISAM不支持事务,InnoDB支持事务

(2)锁级别:MyISAM只支持表级锁,InnoDB支持行级锁和表级锁,默认使用行级锁,但是行锁只有通过索引查询数据才会使用,否则将使用表锁。行级锁在每次获取锁和释放锁的操作需要消耗比表锁更多的资源。使用行锁可能会存在死锁的情况,但是表级锁不存在死锁

(3)主键和外键:MyISAM 允许没有任何索引和主键的表存在,不支持外键。InnoDB的主键不能为空且支持主键自增长,如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键,支持外键完整性约束

(4)索引结构:MyISAM 和 InnoDB 都是使用B+树索引,MyISAM的主键索引和辅助索引的Data域都是保存行数据记录的地址。但是InnoDB的主键索引的Data域保存的不是行数据记录的地址,而是保存该行的所有数据内容,而辅助索引的Data域保存的则是主索引的值。

由于InnoDB的辅助索引保存的是主键索引的值,所以使用辅助索引需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。这也是为什么不建议使用过长的字段作为主键的原因:由于辅助索引包含主键列,所以,如果主键使用过长的字段,将会导致其他辅助索变得更大,所以争取尽量把主键定义得小一些。

(5)全文索引:MyISAM支持全文索引,InnoDB在5.6版本之前不支持全文索引,5.6版本及之后的版本开始支持全文索引

(6)表的具体行数:

  • ① MyISAM:保存有表的总行数,如果使用 select count() from table 会直接取出出该值,不需要进行全表扫描。
  • ② InnoDB:没有保存表的总行数,如果使用 select count() from table 需要会遍历整个表,消耗相当大。

(7)存储结构:

  • ① MyISAM会在磁盘上存储成三个文件:.frm文件存储表定义,.MYD文件存储数据,.MYI文件存储索引。
  • ② InnoDB:把数据和索引存放在表空间里面,所有的表都保存在同一个数据文件中,InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。

(8)存储空间:

  • ① MyISAM:可被压缩,存储空间较小。支持三种不同的存储格式:静态表(默认,但是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。
  • ② InnoDB:需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。

(9)适用场景:

  • ① 如果需要提供回滚、崩溃恢复能力的ACID事务能力,并要求实现行锁级别并发控制,InnoDB是一个好的选择;
  • ② 如果数据表主要用来查询记录,读操作远远多于写操作且不需要数据库事务的支持,则MyISAM引擎能提供较高的处理效率;

备注:在mysql8.0版本中已经废弃了MyISAM存储引擎

 

4、事务的ACID与实现原理?

数据库的事务是并发控制的基本单位,是指逻辑上的一组操作,要么全部执行,要么全部不执行。

4.1、事务的ACID:

  • (1)原子性:事务是一个不可分割的工作单元,事务里的操作要么都成功,要么都失败,如果事务执行失败,则需要进行回滚。
  • (2)隔离性:事务的所操作的数据在提交之前,对其他事务的可见程度。
  • (3)持久性:一旦事务提交,它对数据库中数据的改变就是永久的。
  • (4)一致性:事务不能破坏数据的完整性和业务的一致性。例如在转账时,不管事务成功还是失败,双方钱的总额不变。

4.2、ACID的实现原理:

4.2.1、原子性:原子性是通过MySQL的回滚日志undo log实现的:当事务对数据库进行修改时,InnoDB会生成对应的undo log;如果事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。

4.2.2、隔离性:

(1)事务的隔离级别:

为保证在并发环境下读取数据的完整性和一致性,数据库提供了四种事务隔离级别,隔离级别越高,越能保证数据的完整性和一致性,但对高并发性能影响也越大,执行效率越低。(四种隔离级别从上往下依次升高)

  • 读未提交:允许事务在执行过程中,读取其他事务尚未提交的数据;
  • 读已提交:允许事务在执行过程中读取其他事务已经提交的数据;
  • 可重复读(默认级别):在同一个事务内,任意时刻的查询结果都是一致的;
  • 读序列化:所有事务逐个依次执行,每次读都需要获取表级共享锁,读写会相互阻塞。

(2)事务的并发问题:

如果不考虑事务的隔离性,在事务并发的环境下,可能存在问题有:

  • 更新丢失:两个或多个事务操作相同的数据,然后基于选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题:最后的更新覆盖了其他事务所做的更新。
  • 脏读:指事务A正在访问数据,并且对数据进行了修改(事务未提交),这时,事务B也使用这个数据,后来事务A撤销回滚,并把修改后的数据恢复原值,B读到的数据就与数据库中的数据不一致,即B读到的数据是脏数据。
  • 不可重复读:在一个事务内,多次读取同一个数据,但是由于另一个事务在此期间对这个数据做了修改并提交,导致前后读取到的数据不一致;
  • 幻读:在一个事务中,先后两次进行读取相同的数据(一般是范围查询),但由于另一个事务新增或者删除了数据,导致前后两次结果不一致。

不同的事务隔离级别,在并发环境会存在不同的并发问题:

MySQL数据库常见面试题总结_第1张图片

(3)事务隔离性的实现原理:

Innodb事务的隔离级别是由MVVC和锁机制实现的:

① MVCC(Multi-Version Concurrency Control,多版本并发控制)是 MySQL 的 InnoDB 存储引擎实现事务隔离级别的一种具体方式,用于实现读已提交和可重复读这两种隔离级别。而读未提交隔离级别总是读取最新的数据行,无需使用 MVCC。读序列化隔离级别需要对所有读取的行都加锁,单纯使用 MVCC 无法实现。

MVCC是通过在每行记录后面保存两个隐藏的列来实现的,一个保存了行的事务ID,一个保存了行的回滚段指针。每开始一个新的事务,都会自动递增产生一个新的事务ID。事务开始时会把该事务ID放到当前事务影响的行事务ID字段中,而回滚段的指针有该行记录上的所有版本数据,在undo log回滚日志中通过链表形式组织,也就是说该值实际指向undo log中该行的历史记录链表。

在并发访问数据库时,对正在事务中的数据做MVCC多版本的管理,以避免写操作阻塞读操作,并且可以通过比较版本解决幻读。

② 锁机制:

MySQL锁机制的基本工作原理就是:事务在修改数据库之前,需要先获得相应的锁,获得锁的事务才可以修改数据;在该事务操作期间,这部分的数据是锁定,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。

  • 排它锁解决脏读
  • 共享锁解决不可重复读
  • 临键锁解决幻读

4.2.3、持久性:

持久性的依靠redo log日志实现在执行SQL时会保存已执行的SQL语句到一个redo log文件,但是为了提高效率,将数据写入到redo log之前,会先写入到内存中的redo log buffer缓存区中。写入过程如下:当向数据库写入数据时,执行过程会首先写入redo log buffer,redo log buffer中修改的数据会定期刷新到磁盘的redo log文件中,这一过程称为刷盘(即redo log buffer写日志到磁盘的redo log file中 )。

redo log buffer的使用可以大大提高了读写数据的效率,但是也带了新的问题:如果MySQL宕机,而此时redo log buffer中修改的数据在内存还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。为了确保事务的持久性,在当事务提交时,会调用fsync接口对redo log进行刷盘 ,刷新频率由 innodb_flush_log_at_trx_commit变量来控制的:

  • 0:表示不刷入磁盘;
  • 1:事务每次提交的时候,就把缓冲池中的数据刷新到磁盘中;
  • 2:提交事务的时候,把缓冲池中的数据写入磁盘文件对应的 os cache 缓存里去,而不是直接进入磁盘文件。可能 1 秒后才会把 os cache 里的数据写入到磁盘文件里去。

4.2.4、一致性:

一致性指的是事务不能破坏数据的完整性和业务的一致性 :

  • 数据的完整性: 实体完整性、列完整性(如字段的类型、大小、长度要符合要求)、外键约束等

  • 业务的一致性:例如在银行转账时,不管事务成功还是失败,双方钱的总额不变。

该部分详情可参考这篇博客:https://blog.csdn.net/a745233700/article/details/84207186

 

5、数据库中的锁机制?

当数据库中多个事务并发存取同一数据的时候,若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。MySQL锁机制的基本工作原理就是,事务在修改数据库之前,需要先获得相应的锁,获得锁的事务才可以修改数据;在该事务操作期间,这部分的数据是锁定,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。

按照不同的分类方式,锁的种类可以分为以下几种:

  • 按锁的粒度划分:表级锁、行级锁、页级锁; 
  • 按锁的类型划分:共享(锁S锁)、排他锁(X锁);
  • 按锁的使用策略划分:乐观锁、悲观锁;

5.1、表级锁、行级锁、页级锁:

  • 表级锁:最大粒度的锁级别,发生锁冲突的概率最高,并发度最低,但开销小,加锁快,不会出现死锁;
  • 行级锁:最小粒度的所级别,发生锁冲突的概率最小,并发度最高,但开销大,加锁慢,会发生死锁;
  • 页级锁:锁粒度界于表级锁和行级锁之间,对表级锁和行级锁的折中,并发度一般。开销和加锁时间也界于表锁和行锁之间,会出现死锁;

不同的存储引擎支持不同的锁机制:

  • InnoDB存储引擎支持行级锁和表级锁,默认情况下使用行级锁,但只有通过索引进行查询数据,才使用行级锁,否就使用表级锁。
  • MyISAM和MEMORY存储引擎采用的是表级锁;
  • BDB存储引擎使用的是页面锁,但也支持表级锁;

5.2、InnoDB的行锁:

InnoDB的行锁有两种类型:

  • 共享锁(S锁、读锁):多个事务可以对同一数据行共享一把S锁,但只能进行读不能修改;
  • 排它锁(X锁、写锁):一个事务获取排它锁之后,可以对锁定范围内的数据行执行写操作,在锁定期间,其他事务不能再获取这部分数据行的锁(共享锁、排它锁),只允许获取到排它锁的事务进行更新数据。

对于update,delete,insert 操作,InnoDB会自动给涉及的数据行加排他锁;对于普通SELECT语句,InnoDB不会加任何锁。

5.3、InnoDB的表锁与意向锁:

因为InnoDB引擎允许行锁和表锁共存,实现多粒度的锁机制,但是表锁和行锁虽然锁定范围不同,但是会相互冲突。当你要加表锁时,势必要先遍历该表的所有记录,判断是否有排他锁。这种遍历检查的方式显然是一种低效的方式,MySQL引入了意向锁,来检测表锁和行锁的冲突。

意向锁也是表级锁,分为读意向锁(IS锁)和写意向锁(IX锁)。当事务要在记录上加上行锁时,则先在表上加上对应的意向锁。之后事务如果想进行锁表,只要先判断是否有意向锁存在,存在时则可快速返回该表不能启用表锁,否则就需要等待,提高效率。

5.4、InnoDB行锁的实现与临键锁:

InnoDB的行锁是通过给索引上的索引项加锁来实现的。只有通过索引检索数据,才能使用行锁,否则将使用表锁。

在InnoDB中,为了解决幻读的现象,引入了临键锁(next-key)。根据索引,划分为一个个左开右闭的区间。当进行范围查询的时候,若命中索引且能够检索到数据,则锁住记录所在的区间和它的下一个区间。其实,临键锁(Next-Key) = 记录锁(Record Locks) + 间隙锁(Gap Locks)

  • 间隙锁:当使用范围查询而不是精准查询进行检索数据,并请求共享或排它锁时,InnoDB会给符合范围条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做间隙(GAP)。
  • 记录锁:当使用唯一索引,且记录存在的精准查询时,使用记录锁

5.5、利用锁机制解决并发问题:

  • X锁解决脏读
  • S锁解决不可重复读
  • 临键锁解决幻读

InnoDB存储引擎锁机制的详细内容和MyISAM存储引擎的锁机制的详细内容可以阅读这篇文章:https://blog.csdn.net/a745233700/article/details/84504209

 

(未完待续)

 

6、MySQL索引的实现原理:

7、SQL优化和索引优化:

8、表结构优化:

9、数据库参数优化:

10、explain的执行计划:

11、MySQL的主从复制和读写分离:

MySQL主从复制的原理:Slave 从 Maste r获取 Binary log 二进制日志文件,然后再将日志文件解析成相应的 SQL 语句在从服务器上重新执行一遍主服务器的操作,通过这种方式来保证数据的一致性。由于主从复制的过程是异步复制的,因此Slave和Master之间的数据有可能存在延迟的现象,此时只能保证数据最终的一致性。

12、分库分表:

13、分区:

14、视图:

15、存储过程

16、触发器:

17、游标:

18、drop、truncate、delete的区别?

 

 


相关阅读:

SpringMVC常见面试题总结(超详细回答)

Spring常见面试题总结(超详细回答)

Mybatis常见面试题总结

MySQL常见面试题总结

你可能感兴趣的:(MySQL数据库,mysql,面试)