前言
了解相关的面试题也有助于掌握对应知识。
本文章为番外篇,专门记录所见到的Mysql相关面试题,如有不理解的地方欢迎一起讨论 ~
一、ACID靠什么保证的
A原子性由undo log日志保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql。
C一致性由其他三大特征保证、持续业务代码要保证业务上的一致性。
I隔离性由MVCC来保证。
D持久性由“内存”+“redo log”来保证,mysql修改数据同时在内存和redo log记录这次操作,宕机的时候可以从redo log恢复。
InnoDB redo log 写盘,InnoDB 事务进入 prepare 状态。
如果前面 prepare 成功,binlog 写盘,再继续将事务日志持久化到 binlog,如果持久化成功,那么
InnoDB 事务则进入 commit 状态(在 redo log 里面写一个 commit 记录),所以事务的成功标志是在redo log中有个一个commit记录。
redolog的刷盘会在系统空闲时进行。
二、B树和B+树的区别,为什么Mysql使用B+树
关于B和B+树的区别,请看这篇文章 深入浅出Mysql(一)-Mysql索引底层数据结构与算法
使用B+树的原因是,为了防止树的层级太高影响索引的性能,B+树上层使用的是冗余索引,到底层节点才存有数据,并且叶子节点之间有指针,可以很好的支持全表扫描、范围查找等SQL语句。
三、Explain语句结果中各个字段分别表示什么意思
| 列名 | 描述 |
|---|---|
| id | 查询语句中每出现⼀个SELECT关键字,MySQL就会为它分配⼀个唯⼀的id值,某些查询会被优化为join查询,那么出现的id会⼀样 |
| select_type | SELECT关键字对应的那个查询的类型 |
| table | 表名 |
| partitions | 匹配的分区信息 |
| type | 针对单表的查询⽅式(全表扫描、索引) |
| possible_keys | 可能⽤到的索引 |
| key | 实际上使⽤的索引 |
| key_len | 实际使⽤到的索引⻓度 |
| ref | 当使⽤索引列等值查询时,与索引列进⾏等值匹配的对象信息 |
| rows | 预估的需要读取的记录条数 |
| filtered | 某个表经过搜索条件过滤后剩余记录条数的百分⽐ |
| Extra | ⼀些额外的信息,⽐如排序等 |
更详细的信息可以查看 深入浅出Mysql(二)-Explain理解与索引最佳实战
四、索引覆盖是什么?
索引覆盖就是⼀个SQL在执⾏时,可以利⽤索引来快速查找,并且此SQL所要查询的字段在当前索引对应的字段中都包含了,那么就表示此SQL⾛完索引后不⽤回表了,所需要的字段都在当前索引的叶⼦节点上存在,可以直接作为结果返回了。
需要找的数据都在辅助索引树里面找到了,就不用回表了。
五、最左前缀前缀原则是什么
当⼀个SQL想要利⽤索引,就⼀定要提供该索引所对应的字段中最左边的字段,也就是排在最前⾯的字段。
⽐如针对a,b,c三个字段建⽴了⼀个联合索引,那么在写⼀个sql时就⼀定要提供a字段的条件,这样才能⽤到联合索引,这是由于在建⽴a,b,c三个字段的联合索引时,底层的B+树是按照a,b,c三个字段从左往右去⽐较⼤⼩进⾏排序的,所以如果想要利⽤B+树进⾏快速查找也得符合这个规则。
六、MySQL的集群是如何搭建的?读写分离是怎么做的?
MySQL通过将主节点的Binlog同步给从节点完成主从之间的数据同步。
MySQL的主从集群只会将binlog从主节点同步到从节点,而不会反过来同步。由此也就引申出了读写分离的问题。
因为要保证主从之间的数据一致,写数据的操作只能在主节点完成, 而读数据的操作,可以在主节点或者从节点上完成。
七、mysql聚簇和非聚簇索引的区别
聚簇索引: 将数据存储与索引放到了一块、并且是按照一定的顺序组织的,找到索引也就找到了数据,数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。
非聚簇索引: 叶子节点不存储数据、存储的是数据行地址,也就是说根据索引查找到数据行的位置再取磁盘查找数据,这个就有点类似一本书的目录,比如我们要找第三章第一节,那我们先在这目录里面找,找到对应的页码后再去对应的页码看文章。
优势:
- 查询通过聚簇索引可以直接获取数据,相比非聚簇索引需要第二次查询(非覆盖索引的情况下)效率要高。
- 聚簇索引对于范围查询的效率很高,因为其数据是按照大小排列的。
- 聚簇索引适合用在排序的场合,非聚簇索引不适合。
劣势:
- 维护索引很昂贵,特别是插入新行或者主键被更新导致要分页(page split)的时候。建议在大量插入新行后,选在负载较低的时间段,通过OPTIMIZE TABLE优化表,因为必须被移动的行数据可能造成碎片。使用独享表空间可以弱化碎片。
- 表因为使用UUId(随机ID)作为主键,使数据存储稀疏,这就会出现聚簇索引有可能有比全表扫面更慢,所以建议使用int的auto_increment作为主键。
- 如果主键比较大的话,那辅助索引将会变的更大,因为辅助索引的叶子存储的是主键值;过长的主键值,会导致非叶子节点占用占用更多的物理空间。
八、MySQL慢查询该如何优化?
-
检查是否⾛了索引,如果没有则优化SQL利⽤索引。
-
检查所利⽤的索引,是否是最优索引。
-
检查所查字段是否都是必须的,是否查询了过多字段,查出了多余数据。
-
检查表中数据是否过多,是否应该进⾏分库分表了。
-
检查数据库实例所在机器的性能配置,是否太低,是否可以适当增加资源。
九、MySQL索引结构,各自的优势
阅读下作者下面文章即可理解,如不理解欢迎联系作者~
十、MySQL执行计划怎么看?
阅读下作者下面文章即可理解,如不理解欢迎联系作者~
十一、海量数据下,如何快速查找一条记录?
这是道开放性的问题。 待更新...
十二、Innodb是如何实现事务的?
Innodb通过Buffer Pool,LogBuffer,Redo Log,Undo Log来实现事务,以⼀个update语句为例:
-
Innodb在收到⼀个update语句后,会先根据条件找到数据所在的⻚,并将该⻚缓存在Buffer Pool中
-
执⾏update语句,修改Buffer Pool中的数据,也就是内存中的数据
-
针对update语句⽣成⼀个RedoLog对象,并存⼊LogBuffer中
-
针对update语句⽣成undolog⽇志,⽤于事务回滚
-
如果事务提交,那么则把RedoLog对象进⾏持久化,后续还有其他机制将Buffer Pool中所修改的数据⻚持久化到磁盘中
-
如果事务回滚,则利⽤undolog⽇志进⾏回滚。
十三、锁的类型
更详细的解释请看深入浅出Mysql(五)-原来MySQL锁机制是这么回事
基于锁的属性分类:共享锁、排他锁。
基于锁的粒度分类:行级锁(INNODB)、表级锁(INNODB、MYISAM)、页级锁(BDB引擎)、记录锁、间隙锁、临键锁。
基于锁的状态分类:意向共享锁、意向排它锁。
表锁:
表锁是指上锁的时候锁住的是整个表,当下一个事务访问该表的时候,必须等前一个事务释放了锁才能进行对表进行访问;
特点: 粒度大,加锁简单,容易冲突;
行锁:
行锁是指上锁的时候锁住的是表的某一行或多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问;
特点: 粒度小,加锁比表锁麻烦,不容易冲突,相比表锁支持的并发要高;
记录锁(Record Lock):
记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录。精准条件命中,并且命中的条件字段是唯一索引加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题。
页锁:
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折中的页级,依次锁定相邻的一组记录。
特点:开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般。
间隙锁(Gap Lock):
属于行锁中的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙则会形成一个区间,遵循左开右闭原则。范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_READ(重复读)的事务级别中。
触发条件:防止幻读问题,事务并发的时候,如果没有间隙锁,就会发生如下图的问题,在同一个事务里,A事务的两次查询出的结果会不一样。比如表里面的数据ID 为 1,4,5,7,10 ,那么会形成以下几个间隙区间,-n-1区间,1-4区间,7-10区间,10-n区间 (-n代表负无穷大,n代表正无穷大)
临建锁(Next-Key Lock):
也属于行锁的一种,并且它是INNODB的行锁默认算法,总结来说它就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住,再之它会把相邻的下一个区间也会锁住。
触发条件:范围查询并命中,查询命中了索引。 结合记录锁和间隙锁的特性,临键锁避免了在范围查询时出现脏读、重复读、幻读问题。加了临键锁之后,在范围区间内数据不允许被修改和插入。
十四、Mysql数据库中,什么情况下设置了索引但无法使用?
- 没有符合最左前缀原则。
- 字段进行了隐式数据类型转换。
- 走索引没有全表扫描效率高。
对于“十四”问题,下面两篇文章配合食用更佳~
十五、存储拆分后如何解决唯一主键问题
UUID:简单、性能好,没有顺序,没有业务含义,存在泄漏mac地址的风险。
数据主键:实现简单,单调递增,具有一定的业务可读性,依赖强db,存在性能瓶颈,存在暴露业务信息的风险
引入reids、mongodb、zk等中间件:增加了系统的复杂度和稳定性
雪花算法
十六、怎么处理慢查询?
在业务系统中,除了使用主键进行的查询,其他的都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。
慢查询的优化首先要搞明白慢的原因是什么?是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?
所以优化也是针对这三个方向来的,
-
首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
-
分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。
-
如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。
十七、事务的基本特性和隔离级别
阅读下作者下面文章即可理解,如不理解欢迎联系作者~