暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

10道MySQL面试题

虹猫tomcat 2021-08-18
408

1 MySQL中一条查询语句的执行流程?

    select id , name from student where id =1

    (1)连接器:获取权限,建立连接;

    (2)8.0版本之前可以先查缓存,以key-v的形式存在,key为查询命令,v是数据记录。但不推荐,因为缓存的表任何数据或者结构改变会导致跟这个表相关的缓存失效,因此只适用于数据不经常变的场景。若缓存命中,直接返回,否则下一步;

    (3)分析器:首先词法分析,分析操作类型是select,表是student表,查询字段是id和name,查询条件是id=1;接着是语法分析,判断是否符合SQL语法;

    (4)优化器:选择合适的索引,按照MySQL认为的最优方案执行,比如,数据量小的话,虽然理论上索引更好,但全表扫描效率更高,因此,MySQL会全表扫描而不是走索引。

    (5)执行器:调用引擎层的接口执行查询,返回结果。

    2 MySQL中一条更新语句的执行流程?

      update student set age=18 where id =1

      (1)按照查询语句流程先查询到这条记录,将数据改后变成新的一行调用引擎接口写入;

      (2)引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时redo log处于prepare状态。然后通知执行器自己执行完成了,可以提交事务。

      (3)执行器收到通知后生成这个操作的 binlog,并把 binlog写入磁盘。执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交commit状态,更新完成。先提交事务,再写binlog。

      3 redo log和binlog是什么?为何要用两个日志?

      redo log:InnoDB特有的物理日志,记录的是数据修改之后的值,不管事务是否提交都会记录下来。在数据库异常重启时,InnoDB存储引擎会使用redo log恢复到重启前的时刻,以此来保证数据的完整性。redo log其中可能存在很多未提交事务的数据,因此不可以做数据库备份。

      binlog:MySQL自带的逻辑日志,记录的是所有写命令,只在事务提交完成后进行一次写入,可用于数据库备份。

      先写 redo log 直接提交,然后写 binlog,假设写完 redo log 后,机器挂了,binlog 日志没有被写入,那么机器重启后,这台机器会通过 redo log 恢复数据,但是这个时候 binlog 并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。

      先写 binlog,然后写 redo log,假设写完了 binlog,机器异常重启了,由于没有 redo log,本机是无法恢复这一条记录的,但是 binlog 又有记录,那么和上面同样的道理,就会产生数据不一致的情况。

      如果采用 redo log 两阶段提交的方式就不一样了,写完 binlog 后,然后再提交 redo log 就会防止出现上述的问题,从而保证了数据的一致性。

      极端的情况下,假设 redo log 处于预提交状态,binlog 也已经写完了,这个时候发生了异常重启会怎么样呢?这个要依赖于 MySQL 的处理机制了,判断 redo log 是否完整,如果判断是完整的,就立即提交。如果 redo log 只是预提交但不是 commit 状态,这个时候就会去判断bin log 是否完整,如果完整就提交 redo log, 不完整就回滚事务。

      4 MySQL三大范式?

      范式只是个范式,实际开发中还要以性能为主,往往违背范式更便于开发。

      第一范式:原子性,表中每列不可再分。比如,联系方式:邮箱加电话显然不合适,要分成两列。

      第二范式:在满足第一范式的情况下,表中的每一个字段都完全依赖于主键,不产生局部依赖。极端情况考虑,一个表两个字段组成联合主键,每个字段都要依赖于这个联合主键,不能只依赖于一个联合主键中的一个字段,否则就是部份依赖。

      第三范式:在满足第二范式的情况下,不产生传递依赖,表中每一列都直接依赖主键,而不是通过其他列间接依赖于主键。如学号 姓名 年龄 所在学院、学院地点显然学号(主键)确定了,所在学院就确定了,所在学院确定了,学院地点就确定了。

      5 MySQL有哪些存储引擎及其应用场景?InnoDB和MyISAM存储引擎区别?

      (1)MyISAM:5.5版本之前默认的存储引擎,只支持表锁,效率低;不支持事务和外键;并发效率低,读取数据快,更新数据慢。适合以读为主、对并发要求低的场景。索引数据结构为B+树,非聚簇索引,数据域存的是记录的地址。

      (2)InnoDB:5.5版本之后默认的存储引擎,支持外键、行级锁和事务,适合对并发要求高且增删改较多的场景。索引数据结构为B+树,主键索引为聚簇索引,主键值和数据记录在一起,辅助索引为非聚簇索引,数据域为主键id,到主键索引再去找记录。

      (3)Memory:所有数据保存在内存中,访问速度快,但是断电即失,适合数据量小快速访问的场景。

      6 索引

      索引是什么?索引类型?

      索引是提升查询速度的一种数据结构,在插入数据时对数据进行了排序。索引有以下类型:

      (1)普通索引:加速查询,列值可以重复。

      (2)唯一索引:加速查询,列值唯一但可以为null,例如在name列建索引,要求name不允许重名。

      (3)主键索引:加速查询,列值唯一且不为null。

      (4)全文索引:对文本内容的分词搜索,例如Ctrl+f搜索。

      (5)覆盖索引:查询的数据列包含在索引中,表现为explain执行查询计划时extra列为using index。

      (6)聚簇索引:主键和数据记录存在一起,例如InnoDB的主键索引。

      (7)非聚簇索引:键值和数据分开。

      (8)辅助索引:InnoDB中除了主键索引都是辅助索引,也叫二级索引,也是非聚簇索引。

      (9)组合索引:也叫联合索引、复合索引,对多个列一起建索引,一般如果不是只查一个字段,组合索引是覆盖索引的前提。

      如何创建索引?索引如何选择?

      (1)在频繁查询的字段、不经常改变、需要排序的字段建立索引;

      (2)尽量使用联合索引,可以索引覆盖,效率高于多个独立索引;

      (3)不能在区分度不高的字段建索引,例如性别,无意义。

      索引失效情况?

      (1)联合索引未满足最左匹配原则,where后接多个and时即使不满足最左匹配原则MySQL也会自动优化;

      (2)在索引字段使用了函数或者进行了计算;

      (3)or前后没有同时使用索引;

      (4)在索引字段使用!=、not,<>索引肯定失效,is null、is not null可能失效;

      (5)模糊查询like以%开头;

      (6)数字字符未加单引号,MySQL自动类型转换造成索引失效,字符串未加引号也会导致索引失效;

      (7)全表扫描更快。

      索引数据结构?

      (1)HashTable:速度快,因为在数组中的位置是根据key的hash值决定的,还有哈希冲突,在哈希表不是连续存储的,不能范围查询,需要一次性把数据全部加到内存,数据量大时消耗内存。Memory存储引擎支持。

      (2)B树:M阶二叉树,所有节点既存key又放数据记录,当数据量大时,每个节点存储的记录数很少,树高增加,IO次数也增加,需要遍历所有节点做范围查询,查找不稳定,可能在根节点也可能在叶子节点;

      (3)B+树:非叶子节点仅存索引,数据存在叶子节点,树更矮胖,一次性读入内存的关键字多,降低IO次数,亿级数据仅需3到4次IO,所有叶子节点构成有序链表,只需遍历叶子节点就可以实现整棵树的遍历,可以范围查找。

      7 事务

      事务四大特性?如何实现?

      A:原子性,一个事务中的多个操作要成功都成功,否则都失败回滚事务,由MVCC的undo log 实现。

      C:AID的最终目标就是为了实现一致性。

      I:隔离性,多个事务互不干扰,并发事务时写写操作用锁机制,一写一读可以用MVCC的read view。

      D:持久性,事务处理完,对数据的修改是永久的,即使是系统故障,redo log灾难恢复。

      并发事务带来的问题?事务的隔离级别?如何解决?

      脏读:一个事务读到了另一个事务尚未提交的数据。

      不可重复读:update引起,在同一个事务中对同一数据读取的结果不同。

      幻读:delete、insert引起,在同一个事务中读取表数据多了几行或少了几行。

      更新丢失:最后的更新覆盖了其他事务之前的更新,而事务之间并不知道,发生更新丢失。更新丢失,可以完全避免,对访问的数据加悲观锁或者乐观锁加版本号。

      读未提交:并发事务存在脏读、不可重复读、幻读问题;

      读已提交:解决脏读问题,并发事务存在不可重复读、幻读问题。MVCC建一个快照,只能看到当前事务之前的事务提交的数据。

      可重复读:解决不可重复读问题,并发事务存在幻读问题;但是在MySQL中修复了这一问题,采用MVCC+next-key lock解决。

      串行化:解决幻读问题,通过next-key lock即间隙锁解决。

      8 MVCC

      多版本并发控制,读写冲突不加锁解决,提高数据库性能。由三部分组成:

      三个隐式字段:(1)最后一次修改该记录的事务ID;(2回滚指针,指向记录的上一个版本;(3)隐式ID,表无主键自动生成主键ID。

      undo log:旧记录的版本链;

      read view:当前事务进行快照读某个记录时的那一刻,创建快照,快照中记录了当前活跃的事务ID数组list(递增,ID越大事务越新),根据当前记录的事务ID与活跃事务ID数组比较,判断这条记录的可见性。

      可见性比较规则:当前事务ID为啥不重要,不妨设为x

      (1)看的是这条记录中的DB_TRX_ID字段存的id与list比较,如果DB_TRX_ID<min(list),说明这条记录已提交,可以被x看到;

      (2)若DB_TRX_ID>max(list),说明这条记录尚未提交,不可以被x看到;

      (3)若DB_TRX_ID等于list中的某个ID,说明这条记录尚未提交,也不可以被x看到;

      (4)以上情况都排除,则说明这条记录肯定在某个时刻被提交,对x可见。


      参考文末的文章,讲解的十分Nice。

      9 MySQL简单优化?

      (1)通过慢查询日志定位执行时间较长的SQL,慢查询日志只能看到执行完成的SQL;使用show processlist命令可以实时查看正在运行的线程;

      (2)使用explain查看待优化SQL的执行计划,判断索引选择是否合理进行优化;

      (3)show profiles可以看时间消耗在哪里;

      (4)数据量大是否需要分库分表。

      10 主从同步?

      主库负责写,从库负责读,避免主库表锁住导致无法读的情形,多台机器合作提高单机的IO性能,从机也可以做热备份。
      同步过程:

      (1)主库写命令更新到binlog;

      (2)主库创建一个binlog dump thread,把binlog的内容发送到从库(从节点监听,定期pull)

      (3)从库创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log

      (4)从库创建一个SQL线程,从relay log里面读取内容并对数据更新。

      从库通过创建两个独立的线程,使得在进行复制时,从库的读和写进行了分离,即使负责执行的线程运行较慢,负责读取更新语句的线程并不会因此变得缓慢,可以让数据备份在relay log中。


      参考文章:https://www.jianshu.com/p/8845ddca3b23

      文章转载自虹猫tomcat,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论