Mysql面试题

307 阅读13分钟

什么是最左前缀原则?什么是最左匹配原则

当⼀个SQL想要利⽤索引是,就⼀定要提供该索引所对应的字段中最左边的字段,也就是排在最前⾯的字段,⽐如针对a,b,c三个字段建⽴了⼀个联合索引,那么在写⼀个sql时就⼀定要提供a字段的条件,这样才能⽤到联合索引,这是由于在建⽴a,b,c三个字段的联合索引时,底层的B+树是按照a,b,c三个字段从左往右去⽐较⼤⼩进⾏排序的,所以如果想要利⽤B+树进⾏快速查找也得符合这个规则

关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

在业务系统中,除了使用主键进行的查询,其他的都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。慢查询的优化首先要搞明白慢的原因是什么?是查询条件没有命中索引?是查询了不需要的数据列?还是数据量太大?

所以优化也是针对这三个方向来的

  • 首先分析语句,看看是否查询了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
  • 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。
  • 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

Mysql慢查询该如何优化?

  1. 检查是否⾛了索引,如果没有则优化SQL利⽤索引

  2. 检查所利⽤的索引,是否是最优索引

  3. 检查所查字段是否都是必须的,是否查询了过多字段,查出了多余数据

  4. 检查表中数据是否过多,是否应该进⾏分库分表了

  5. 检查数据库实例所在机器的性能配置,是否太低,是否可以适当增加资源

谈谈如何对MySQL进行分库分表

什么是分库分表? 当表中数据量过大时,整个查询效率就会降低的非常明显,这时为了提升查询效率,就要将一个表中的数据分散到多个表当中。

索引覆盖是什么?

索引覆盖就是⼀个SQL在执⾏时,可以利⽤索引来快速查找,并且此SQL所要查询的字段在当前索引对应的字段中都包含了,那么就表示此SQL⾛完索引后不⽤回表了,所需要的字段都在当前索引的叶⼦节点上存在,可以直接作为结果返回了

索引设计的原则?

查询更快、占用空间更小

  1. 适合索引的列是出现在where子句中的列,或者连接子句中指定的列

  2. 基数较小的表,索引效果较差,没有必要在此列建立索引

  3. 使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间,如果搜索词超过索引前缀长度,则使用索引排除不匹配的行,然后检查其余行是否可能匹配。

  4. 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。

  5. 定义有外键的数据列一定要建立索引。

  6. 更新频繁字段不适合创建索引

  7. 若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)

  8. 尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可

  9. 对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。

  10. 对于定义为text、image和bit的数据类型的列不要建立索引。

索引的基本原理

索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。

索引的原理:就是把无序的数据变成有序的查询

  1. 把创建了索引的列的内容进行排序

  2. 对排序结果生成倒排表

  3. 在倒排表内容上拼上数据地址链

  4. 在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据

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 记录)

B树和B+树的区别,为什么Mysql使用B+树?

B树的特点:

  1. 节点排序

  2. ⼀个节点了可以存多个元素,多个元素也排序了

B+树的特点:

  1. 拥有B树的特点

  2. 叶⼦节点之间有指针

  3. ⾮叶⼦节点上的元素在叶⼦节点上都冗余了,也就是叶⼦节点中存储了所有的元素,并且排好顺序,其中用双向指针链接

Mysql索引使⽤的是B+树,因为索引是⽤来加快查询的,⽽B+树通过对数据进⾏排序所以是可以提⾼查询速度的,然后通过⼀个节点中可以存储多个元素,从⽽可以使得B+树的⾼度不会太⾼,在Mysql中⼀个Innodb⻚就是⼀个B+树节点,⼀个Innodb⻚默认16kb,所以⼀般情况下⼀颗两层的B+树可以存2000万⾏左右的数据,然后通过利⽤B+树叶⼦节点存储了所有数据并且进⾏了排序,并且叶⼦节点之间有指针,可以很好的⽀持全表扫描,范围查找等SQL语句

Explain语句结果中各个字段分表表示什么

列名描述
id查询语句中每出现⼀个SELECT关键字,MySQL就会为它分配⼀个唯⼀的id值,某些⼦查询会被优化为join查询,那么出现的id会⼀样
select_typeSELECT关键字对应的那个查询的类型
table表名
partitions匹配的分区信息
type针对单表的查询⽅式(全表扫描、索引)
possible_keys可能⽤到的索引
key实际上使⽤的索引
key_len实际使⽤到的索引⻓度
ref当使⽤索引列等值查询时,与索引列进⾏等值匹配的对象信息
rows预估的需要读取的记录条数
filtered某个表经过搜索条件过滤后剩余记录条数的百分⽐
Extra⼀些额外的信息,⽐如排序等

什么是MVCC?

多版本并发控制:读取数据时通过一种类似快照的方式将数据保存下来,这样读锁就和写锁不冲突了,不同的事务session会看到自己特定版本的数据,版本链MVCC只在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下工作。其他两个隔离级别够和MVCC不兼容, 因为 READ UNCOMMITTED 总是读取最新的数据行, 而不是符合当前事务版本的数据行。而 SERIALIZABLE 则会对所有读取的行都加锁。

聚簇索引记录中有两个必要的隐藏列:

trx_id:用来存储每次对某条聚簇索引记录进行修改的时候的事务id。

roll_pointer:每次对哪条聚簇索引记录有修改的时候,都会把老版本写入undo日志中。这个roll_pointer就是存了一个指针,它指向这条聚簇索引记录的上一个版本的位置,通过它来获得上一个版本的记录信息。(注意插入操作的undo日志没有这个属性,因为它没有老版本)

Innodb是如何实现事务的?

Innodb通过Buffer Pool,LogBuffer,Redo Log,Undo Log来实现事务,以⼀个

update语句为例:

  1. Innodb在收到⼀个update语句后,会先根据where条件找到数据所在的⻚,并将该⻚缓存在Buffer Pool中

  2. 执⾏update语句,修改Buffer Pool中的数据,也就是内存中的数据

  3. 针对update语句⽣成⼀个RedoLog对象,并存⼊LogBuffer中

  4. 针对update语句⽣成undolog⽇志,⽤于事务回滚

  5. 如果事务提交,那么则把RedoLog对象进⾏持久化,后续还有其他机制将Buffer Pool中所修改的数据⻚持久化到磁盘中6. 如果事务回滚,则利⽤undolog⽇志进⾏回滚

红黑树结构

二叉查找树(BST)

1.左子树上所有结点的值均小于或等于它的根结点的值。

2.右子树上所有结点的值均大于或等于它的根结点的值。

3.左、右子树也分别为二叉排序树

二叉查找树多次插入新节点导致不平衡,变成线性查找

红黑树特点

1.结点是红色或黑色。

2.根结点是黑色。

3.每个叶子结点都是黑色的空结点(NIL结点)。

4 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)

5.从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。

mysql聚簇和非聚簇索引的区别

  • 聚簇索引:将数据存储与索引放到了一块、并且是按照一定的顺序组织的,找到索引也就找到了数据,数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的
  • 非聚簇索引:叶子节点不存储数据、存储的是数据行地址,也就是说根据索引查找到数据行的位置再取磁盘查找数据,这个就有点类似一本树的目录,比如我们要找第三章第一节,那我们先在这个目录里面找,找到对应的页码后再去对应页码看文章

InnoDB中一定有主键,主键一定是聚簇索引,不手动设置、则会使用unique索引,没有unique索引,则会使用数据库内部的一个行的隐藏id来当作主键索引。

在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是行的物理位置,而是主键值

MyISM使用的是非聚簇索引,没有聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。如果涉及到大数据量的排序、全表扫描、count之类的操作的话,还是MyISAM占优势些,因为索引所占空间小,这些操作是需要在内存中完成的。

简述MyISAM和InnoDB的区别

MyISAM:

不支持事务,但是每次查询都是原子的;

支持表级锁,即每次操作是对整个表加锁;

存储表的总行数;

一个MYISAM表有三个文件:索引文件、表结构文件、数据文件;采用非聚集索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引不用保证唯一性。

InnoDb:

支持ACID的事务,支持事务的四种隔离级别;

支持行级锁及外键约束:因此可以支持写并发;不存储总行数;

一个InnoDb引擎存储在一个文件空间(共享表空间,表大小不受操作系统控制,一个表可能分布在多个文件里),也有可能为多个(设置为独立表空,表大小受操作系统文件大小限制,一般为2G),受操作系统文件大小的限制;

主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅索引查找数据,需要先通过辅索引找到主键值,再访问辅索引;最好使用自增主键,防止插入数据时,为维持B+树结构,文件的大调整。

为什么建议InnoDB表必须建主键,并且推荐使用整型的自增主键?

  • 整型:整型比大小快,索引速度会快,占空间小
  • 自增:减少树的变化(不是自增容易导致树的分列平衡)

为什么非主键索引结构叶子节点存储的是主键值?

  • 一致性和节省存储空间(如果列数据太多,浪费存储空间)
  • 减少复杂度(如果两个索引都要插入,可以先在一级索引插入数据,再去建立二级索引,只需要把一级索引的数据拿过来就可以了)