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

Author: Xcourse   2023-Mar-15 14:50   Reads: 809

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

官方邮箱:enquiry@xcourse.sg

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

WhatsApp群:@Singapore Jobs & Internships

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

Telegram英文群:@Singapore Jobs

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

 

(下一篇:MySQL 面试题集合 II - 读写分离,事物,MVCC,锁

 

1. 请说下你对 MySQL 架构的了解?

image-20210607164532308

大体来说,MySQL 可以分为 Server 层和存储引擎两部分。

Server 层包括:连接器、查询缓存、分析器、优化器、执行器等,涵盖了 MySQL 的大多数核心服务功能,以及所有的内置函数(如:日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如:存储过程、触发器、视图等等。

存储引擎层负责:数据的存储和提取。其架构是插件式的,支持 InnoDB、MyISAM 等多个存储引擎。从 MySQL5.5.5 版本开始默认的是InnoDB,但是在建表时可以通过 engine = MyISAM 来指定存储引擎。不同存储引擎的表数据存取方式不同,支持的功能也不同。

从上图中可以看出,不同的存储引擎共用一个 Server 层,也就是从连接器到执行器的部分。

 

2. 一条 SQL 语句在数据库框架中的执行流程?

  1. 应用程序把查询 SQL 语句发送给服务器端执行;
  2. 查询缓存,如果查询缓存是打开的,服务器在接收到查询请求后,并不会直接去数据库查询,而是在数据库的查询缓存中找是否有相对应的查询数据,如果存在,则直接返回给客户端。只有缓存不存在时,才会进行下面的操作;
  3. 查询优化处理,生成执行计划。这个阶段主要包括解析 SQL、预处理、优化 SQL 执行计划;
  4. MySQL 根据相应的执行计划完成整个查询;
  5. 将查询结果返回给客户端。
  6. 详情: https://blog.csdn.net/pcwl1206/article/details/86137408

 

3. 数据库的三范式是什么?

数据库的三范式包括:

第一范式(1NF):数据表中的每个属性都是原子性的,不可再分。

第二范式(2NF):数据表中的非主键列都要完全依赖于主键列。

第三范式(3NF):任何非主属性不依赖于其它非主属性。

 

4. char 和 varchar 的区别?

char(n) :固定长度类型,比如:订阅 char(10),当你输入”abc”三个字符的时候,它们占的空间还是 10 个字节,其他 7 个是空字节。char 优点:效率高;缺点:占用空间;适用场景:存储密码的 md5 值,固定长度的,使用 char 非常合适。

varchar(n) :可变长度,存储的值是每个值占用的字节再加上一个用来记录其长度的字节的长度。

所以,从空间上考虑 varcahr 比较合适;从效率上考虑 char 比较合适,二者使用需要权衡。

 

5. varchar(10) 和 varchar(20) 的区别?

varchar(10) 中 10 的涵义最多存放 10 个字符,varchar(10) 和 varchar(20) 存储 hello 所占空间一样,但后者在排序时会消耗更多内存,因为 order by col 采用 fixed_length 计算 col 长度

 

6. 谈谈你对索引的理解?

索引的出现是为了提高数据的查询效率,就像书的目录一样。一本500页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,那我估计你可得找一会儿。同样,对于数据库的表而言,索引其实就是它的“目录”。

同样索引也会带来很多负面影响:创建索引和维护索引需要耗费时间,这个时间随着数据量的增加而增加;索引需要占用物理空间,不光是表需要占用数据空间,每个索引也需要占用物理空间;当对表进行增、删、改、的时候索引也要动态维护,这样就降低了数据的维护速度。

建立索引的原则:

在最频繁使用的、用以缩小查询范围的字段上建立索引;

在频繁使用的、需要排序的字段上建立索引。

不适合建立索引的情况:

对于查询中很少涉及的列或者重复值比较多的列,不宜建立索引;

对于一些特殊的数据类型,不宜建立索引,比如:文本字段(text)等。

 

7. 索引的底层使用的是什么数据结构?

索引的数据结构和具体存储引擎的实现有关,,在MySQL中使用较多的索引有 Hash 索引、B+树索引等。而我们经常使用的 InnoDB 存储引擎的默认索引实现为 B+ 树索引。

 

8. 谈谈你对 B+ 树的理解?

  1. B+ 树是基于 B 树和叶子节点顺序访问指针进行实现,它具有 B 树的平衡性,并且通过顺序访问指针来提高区间查询的性能。
  2. 在 B+ 树中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 key i 和 key i+1,且不为 null,则该指针指向节点的所有 key 大于等于 key i 且小于等于 key i+1。
  3. 进行查找操作时,首先在根节点进行二分查找,找到一个 key 所在的指针,然后递归地在指针所指向的节点进行查找。直到查找到叶子节点,然后在叶子节点上进行二分查找,找出 key 所对应的 data。
  4. 插入、删除操作会破坏平衡树的平衡性,因此在插入删除操作之后,需要对树进行一个分裂、合并、旋转等操作来维护平衡性。

 

9. 为什么 InnoDB 存储引擎选用 B+ 树而不是 B 树呢?

用 B+ 树不用 B 树考虑的是 IO 对性能的影响,B 树的每个节点都存储数据,而 B+ 树只有叶子节点才存储数据,所以查找相同数据量的情况下,B 树的高度更高,IO 更频繁。数据库索引是存储在磁盘上的,当数据量大时,就不能把整个索引全部加载到内存了,只能逐一加载每一个磁盘页(对应索引树的节点)。

 

10. 谈谈你对聚簇索引的理解?

聚簇索引是对磁盘上实际数据重新组织以按指定的一个或多个列的值排序的算法。特点是存储数据的顺序和索引顺序一致。一般情况下主键会默认创建聚簇索引,且一张表只允许存在一个聚簇索引。

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

聚簇索引的叶子节点就是数据节点,而非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针。

 

11. 谈谈你对哈希索引的理解?

哈希索引能以 O(1) 时间进行查找,但是失去了有序性。无法用于排序与分组、只支持精确查找,无法用于部分查找和范围查找。

InnoDB 存储引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B+ 树索引之上再创建一个哈希索引,这样就让 B+Tree 索引具有哈希索引的一些优点,比如:快速的哈希查找。

 

12. 谈谈你对覆盖索引的认识?

如果一个索引包含了满足查询语句中字段与条件的数据就叫做覆盖索引。具有以下优点:

索引通常远小于数据行的大小,只读取索引能大大减少数据访问量。

一些存储引擎(例如:MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用(通常比较费时)。

对于 InnoDB 引擎,若辅助索引能够覆盖查询,则无需访问主索引。

 

13. 索引的分类?

  1. 从数据结构角度
    1. 树索引 (O(log(n)))
    2. Hash 索引
  2. 从物理存储角度
    1. 聚集索引(clustered index)
    2. 非聚集索引(non-clustered index)
  3. 从逻辑角度
    1. 普通索引
    2. 唯一索引
    3. 主键索引
    4. 联合索引
    5. 全文索引

 

14. 谈谈你对最左前缀原则的理解?

MySQL 使用联合索引时,需要满足最左前缀原则。下面举例对其进行说明:

1. 一个 2 列的索引 (name, age),对 (name)、(name, age) 上建立了索引;

2. 一个 3 列的索引 (name, age, sex),对 (name)、(name, age)、(name, age, sex) 上建立了索引。

 

1、 B+ 树的数据项是复合的数据结构,比如:(name, age, sex) 的时候,B+ 树是按照从左到右的顺序来建立搜索树的,比如:当(小明, 22, 男)这样的数据来检索的时候,B+ 树会优先比较 name 来确定下一步的所搜方向,如果 name 相同再依次比较 age 和 sex,最后得到检索的数据。但当 (22, 男) 这样没有 name 的数据来的时候,B+ 树就不知道第一步该查哪个节点,因为建立搜索树的时候 name 就是第一个比较因子,必须要先根据 name 来搜索才能知道下一步去哪里查询。

2、 当 (小明, 男) 这样的数据来检索时,B+ 树可以用 name 来指定搜索方向,但下一个字段 age 的缺失,所以只能把名字等于小明的数据都找到,然后再匹配性别是男的数据了, 这个是非常重要的性质,即索引的最左匹配特性。

关于最左前缀的补充:

  1. 最左前缀匹配原则会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如:a = 1 and b = 2 and c > 3 and d = 4 如果建立 (a, b, c, d) 顺序的索引,d 是用不到索引的。如果建立 (a, b, d, c) 的索引则都可以用到,a、b、d 的顺序可以任意调整。
  2. = 和 in 可以乱序,比如:a = 1 and b = 2 and c = 3 建立 (a, b ,c) 索引可以任意顺序,MySQL 的优化器会优化成索引可以识别的形式。

 

15. 怎么知道创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

使用 Explain 命令来查看语句的执行计划,MySQL 在执行某个语句之前,会将该语句过一遍查询优化器,之后会拿到对语句的分析,也就是执行计划,其中包含了许多信息。可以通过其中和索引有关的信息来分析是否命中了索引,例如:possilbe_key、key、key_len 等字段,分别说明了此语句可能会使用的索引、实际使用的索引以及使用的索引长度。

 

16. 什么情况下索引会失效?即查询不走索引?

下面列举几种不走索引的 SQL 语句:

1、索引列参与表达式计算:

SELECT 'sname' FROM 'stu' WHERE 'age' + 10 = 30;

MysqlCopy

2、 函数运算:

SELECT 'sname' FROM 'stu' WHERE LEFT('date',4) < 1990;

MysqlCopy

3、%词语%–模糊查询:

SELECT * FROM 'manong' WHERE `uname` LIKE '码农%' -- 走索引

 

SELECT * FROM 'manong' WHERE `uname` LIKE '%码农%' -- 不走索引

MysqlCopy

4、 字符串与数字比较不走索引:

“`mysql

CREATE TABLE 'a' ('a' char(10));

EXPLAIN SELECT * FROM 'a' WHERE 'a'="1" — 走索引

EXPLAIN SELECT * FROM 'a'WHERE 'a'=1 — 不走索引,同样也是使用了函数运算

“`

5、 查询条件中有 or ,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引:

select * from dept where dname='xxx' or loc='xx' or deptno = 45;

MysqlCopy

6、正则表达式不使用索引。

7、 MySQL 内部优化器会对 SQL 语句进行优化,如果优化器估计使用全表扫描要比使用索引快,则不使用索引。

 

17. 查询性能的优化方法?

  1. 减少请求的数据量
  2. 只返回必要的列:最好不要使用 SELECT * 语句。
  3. 只返回必要的行:使用 LIMIT 语句来限制返回的数据。
  4. 缓存重复查询的数据:使用缓存可以避免在数据库中进行查询,特别在要查询的数据经常被重复查询时,缓存带来的查询性能提升将会是非常明显的。
  5. 减少服务器端扫描的行数
  6. 最有效的方式是使用索引来覆盖查询。

 

18. InnoDB 和 MyISAM 的比较?

  1. 事务:MyISAM不支持事务,InnoDB支持事务;
  2. 全文索引:MyISAM 支持全文索引,InnoDB 5.6 之前不支持全文索引;
  3. 关于 count():MyISAM会直接存储总行数,InnoDB 则不会,需要按行扫描。意思就是对于 select count() from table; 如果数据量大,MyISAM 会瞬间返回,而 InnoDB 则会一行行扫描;
  4. 外键:MyISAM 不支持外键,InnoDB 支持外键;
  5. 锁:MyISAM 只支持表锁,InnoDB 可以支持行锁。

 

19. 谈谈你对水平切分和垂直切分的理解?

水平切分

水平切分是将同一个表中的记录拆分到多个结构相同的表中。当一个表的数据不断增多时,水平切分是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。

 

垂直切分

垂直切分是将一张表按列切分成多个表,通常是按照列的关系密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用的列切分到不同的表中。例如:将原来的电商数据库垂直切分成商品数据库、用户数据库等。

 

20. 主从复制中涉及到哪三个线程?

主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。

  1. binlog 线程 :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
  2. I/O 线程 :负责从主服务器上读取二进制日志,并写入从服务器的重放日志(Relay log)中。
  3. SQL 线程 :负责读取重放日志并重放其中的 SQL 语句。

 

21. 主从同步的延迟原因及解决办法?

主从同步的延迟的原因:

假如一个服务器开放 N 个连接给客户端,这样有会有大并发的更新操作, 但是从服务器的里面读取 binlog 的线程仅有一个, 当某个 SQL 在从服务器上执行的时间稍长或者由于某个 SQL 要进行锁表就会导致主服务器的 SQL 大量积压,未被同步到从服务器里。这就导致了主从不一致, 也就是主从延迟。

主从同步延迟的解决办法:

实际上主从同步延迟根本没有什么一招制敌的办法, 因为所有的 SQL 必须都要在从服务器里面执行一遍,但是主服务器如果不断的有更新操作源源不断的写入,那么一旦有延迟产生,那么延迟加重的可能性就会原来越大。当然我们可以做一些缓解的措施。

  1. 我们知道因为主服务器要负责更新操作, 它对安全性的要求比从服务器高,所有有些设置可以修改,比如sync_binlog=1,innodb_flush_log_at_trx_commit = 1 之类的设置,而 slave 则不需要这么高的数据安全,完全可以将 sync_binlog 设置为 0 或者关闭 binlog、innodb_flushlog、innodb_flush_log_at_trx_commit 也 可以设置为 0 来提高 SQL 的执行效率。
  2. 增加从服务器,这个目的还是分散读的压力, 从而降低服务器负载。

 

 


Tags: interview mysql backend

Topics: 面经