十道MySQL必问面试题

news2024/9/20 18:53:36
  1. 你是如何理解最左前缀原则的?
  2. 你是如何理解行锁、GAP锁、临键锁的?
  3. 你是如何理解MVCC的?
  4. 你是如何理解count(*)和count(1)的?
  5. 你是如何理解Online DDL的?
  6. 你知道哪些情况下会导致索引失效?
  7. 你是如何理解filesort的?
  8. 你知道哪些情况下会锁表吗?
  9. 你是如何理解MySQL里面的死锁机制的?
  10. 你是如何优化慢查询的?

更多面试题在公众号:IT周瑜

你是如何理解最左前缀原则的?

创建一个表:

CREATE TABLE t1 (
  id int primary key auto_increment,
  a int,
  b int,
  c int,
  d int
);

创建了一个abc联合索引:

alter table t1 add index idx_abc(a, b, c);

执行:

explain select * from t1 where b=1 and c=1 and a=1;

以上SQL能走abc联合索引吗?注意a=1在where条件的最右边哦。

答案是可以的:
image.png

把a=1放到中间:

explain select * from t1 where b=1 and a=1 and c=1;

一样是可以的:
image.png

那把a=1放到最左边就肯定更没问题了

explain select * from t1 where a=1 and b=1 and c=1;

image.png

从这可以看出,不管a=1放在哪个位置,以上SQL都能走索引,那如果把a=1去掉呢?

explain select * from t1 where b=1 and c=1;

此时就不会走abc联合索引了,而是全表扫描:
image.png

从这可以看出,所谓的最左前缀原则中的“最左”,并不是指where条件中a=1一定要在最左边,而是指where条件中一定要给出定义联合索引时的最左边字段,比如我们定义abc联合索引的SQL为:

alter table t1 add index idx_abc(a, b, c);

其中a字段是最左边的字段,因此如果想要走idx_abc索引,那么SQL中就一定要给出a字段的条件,这才是“最左”的意思。

你是如何理解行锁、GAP锁、临键锁的?

假如有以下表:

CREATE TABLE t1 (
  id int primary key,
  name varchar(10)
);

假如表中有两行记录:
image.png
如果我现在执行以下SQL,想要更新id=3的这一行记录:

update t1 set name='dadudu' where id = 3;

此时当前事务会给id=3这一行加一个行锁,其他事务如果也想要更新这一行也需要给这一行加锁,而且两个事务加的都是X锁,也就是排他锁,两个排他锁是不兼容的,所以其他事务只能等待持有锁的事务提交后将锁释放掉才能获取到锁,从而更新数据,这也可以理解为悲观锁。

所谓行锁其实在InnoDB源码中是通过一个lock_t和一个hash表来实现的,这里就不展开分析了,想在面试的时候装B的同学可以联系我,我单独给你分析分析。

行锁锁的是某一行,而GAP锁锁的是行前面的间隙,注意只是行前面的间隙,你可能会问那表的最后一行前后都有间隙啊,最后一行后面的间隙不锁吗?

当然会所了,只不过是交给了一个叫做PAGE_NEW_SUPREMUM的记录来说的,你可以理解为PAGE_NEW_SUPREMUM记录是InnoDB默认的,它固定作为最后一条记录,因此只要锁住PAGE_NEW_SUPREMUM前面的间隙,就相当了锁住了我们所理解的最后一行后面的间隙

而临键锁,也就是next-key锁,它既锁行又锁行前面的间隙,而且我们经常遇到的是行锁或临键锁。

比如上面的SQL:

update t1 set name='dadudu' where id = 3;

由于是根据id进行的更新,id是主键,是唯一的,这种情况就只需要对id=3这条记录加行锁就可以了,并不需要加next-key锁,也就是并不需要锁id=3前面的间隙,因为id=3前面的间隙对应的记录一定不是id=3,所以不用锁间隙。

而如果是下面这个SQL:

update t1 set name='dadudu' where name = 'zhouyu';

就需要锁全部的间隙了,因为全部的间隙都有可能插入name='zhouyu’的记录,或者可以理解为会给所有记录都加临键锁,这样就锁住了所有的间隙。

你是如何理解MVCC的?

所谓MVCC就是多版本并发控制,MySQL为了实现可重复读这个隔离级别,而且为了不采用锁机制来实现可重复读,所以采用MVCC机制来实现。

当一个事务修改一条记录时,会将记录的历史版本也记录下来,从而一条记录会对应一条版本链,而且每次修改时都会将当前的事务ID保存下来,所以一条记录的多个版本可能对应了不同的事务ID,而且在InnoDB中,事务ID是自增的,是有顺序的。

因此,当一个事务在查询某一条记录时,会根据自己的事务ID以及这条记录的版本链,来判断当前事务可见的是哪个版本,从而读出这个版本对应的记录,从而实现了可重复读。

MVCC中还有一个概念就是ReadView,在一个事务首次执行查询时,会创建一个ReadView,而ReadView中会记录当前整个InnoDB中有哪些活跃的事务ID,最大的事务ID,最小的事务ID,然后根据这些信息来判断某条记录的某个版本是否可见,比如:

  1. 如果某个版本的事务ID,比ReadView中最小的事务ID,还要小,那么此版本可见,因为表示该版本的事务是在本事务之前就已经提交了
  2. 如果某个版本的事务ID,属于ReadView中活跃事务,那么此版本不可见,因为表示该版本的事务并不是本事务之前就已经提交了
  3. 如果某个版本的事务ID,比ReadView中最大的事务ID,还要大,那么此版本不可见,因为表示该版本的事务是本事务之后开启的新事务

如果某个版本对当前ReadView不可见,那就继续取上一个版本,直到对当前ReadView可见。

你是如何理解count(*)和count(1)的?

这两个并没有区别,不要觉得count()会查出全部字段,而count(1)不会,所以count()会更慢,你觉得MySQL作者会这么做吗?

我看了MySQL源码,也写了对应了文章麻烦不要再问我count(*)、count(1)、count(id)、count(name)之间的区别了

可以很明确的告诉你们count()和count(1)是一样的,而正确有区别的是count(字段),如果你count()的是具体的字段,那么MySQL会判断某行记录中对应字段是否为null,如果为null就不会进行统计了,因此count(字段)的结果可能会小于count()和count(1)。

另外,直接执行select (*) from t1;也是可以利用到索引的,并不一定是全表扫描,也可以扫描某个索引B+树的叶子节点,从而得到总条数,因为不管是什么索引,主键索引还是辅助索引,实际上它们对应的B+树中的叶子节点中的数据条数是一样的,只不过字段数不一样,主键索引存了全部字段,而辅助索引只存了定义的索引字段+主键字段,所以通常辅助索引是要比主键索引小的,因此遍历起来也会更快,但是记录条数是一样的。

你是如何理解Online DDL的?

一般DDL操作,比如新增字段,会有三个步骤:

  • 第一,新建一个临时表,表的字段是原始表字段和新增字段
  • 第二,将原始表中的数据复制到临时表中
  • 第三,删除原始表,并将临时表重命名为原始表的表名

Online DDL表示在复制数据的过程中允许其他数据库连接读取数据、删除数据、修改数据、新增数据,但并不是所有的DDL操作都支持Online,那些需要修改现有表数据的DDL就不支持,比如新增带有默认值的字段,所谓Online,其实对应的是Inplace算法,在执行DDL时,MySQL会自动判断应该用Copy算法还是Inplace算法,能用Inplace算法的DDL就是Online DDL,MySQL8中,新增了一种效率更高的DDL算法,叫做Instant,算法效率更高,但支持的DDL场景更加有限。

你知道哪些情况下会导致索引失效?

最常见的就是对索引列做了运算、函数操作、类型转换了,比如:

CREATE TABLE t1 (
  id int primary key,
  name varchar(10),
  age varchar(2)
);
insert into t1(id, name, age) values(3, 'zhouyu', '18');
insert into t1(id, name, age) values(6, 'zhangfei', '19');
alter table t1 add index idx_name(name);
alter table t1 add index idx_age(age);

以下SQL是能走索引的:

explain select * from t1 where name = 'zhou';

image.png

但是如果改成:

explain select * from t1 where substring(name, 1, 4) = 'zhou';

image.png
就变成了全表扫描。

还有就是一种常见的索引失效就是对索引列进行类型转换,在MySQL中会将字符串转成数字,所以如果是以下SQL能走索引:

explain select * from t1 where age = '18';

image.png

但是如果是:

explain select * from t1 where age = 18;

image.png
就变成了全表扫描,因为age字段的类型是varchar,而给的值是数字,MySQL需要把age字段的所有内容都转成数字之后再进行where条件的过滤。

你是如何理解filesort的?

首先,order by、group by都有可能触发filesort,因为它们都需要对数据按指定字段进行排序,当然group by也可以不排序,只不过它默认会进行排序。

如果order by指定的字段能走索引,那就不会触发filesort,因为索引本身已经有顺序了,按索引上的顺序直接返回结果就可以了。

如果order by指定的字段不能走索引,此时就会出现filesort,但是不一定代表一定会用到文件排序,实际上MySQL中的order by的大体实现思路是这样的:

具体可参考我写的另外一篇文章假如你是MySQL作者,你会如何实现order by?

你知道哪些情况下会锁表吗?

  1. 表的元数据锁,比如在执行一些DDL操作时,比如给表增加字段,这其实就是在修改表的元数据,因此会给表加元数据锁,如果此时有其他DDL操作也来加元数据锁,那么就会阻塞,此时就出现了锁表
  2. 自增锁,如果一个表的主键是自增id,那么每次新增一条记录时,就需要先获取自增锁,然后得到最新的主键id,然后释放自增锁,然后插入新记录,在这个过程中也可能会短暂的锁表,因为自增锁也是表级别的锁
  3. 还有一种就是表中的所有行和间隙都被锁了,就像前面提到的update语句,也相当于出现了锁表现象

你是如何理解MySQL里面的死锁机制的?

所谓死锁就是:

  1. 事务A对记录1加锁
  2. 事务B对记录2加锁
  3. 事务A想对记录2加锁,阻塞
  4. 事务B想对记录1加锁,阻塞

两个事务都需要等待对方释放锁才能往下执行,此时就出现了死锁,而出现死锁的原因就是两个事务的加锁顺序不一样,如果都是先对记录1加锁,再对记录2加锁,就不会出现死锁现象了。

不过在MySQL中有死锁检查机制,在加锁时会自动判断当前是否出现了死锁,比如上面的第4步,MySQL一旦发现了死锁就会直接报错,从而导致事务B回滚并释放所有锁,从而导致事务A能正常执行下去,最终不会形成死锁。

image.png

另外需要注意,如果加锁请求比较多,死锁检查机制可能会比较消耗性能,此时可以选择关闭死锁检查机制,参数为innodb_deadlock_detect

你是如何优化慢查询的?

  1. 首先肯定是检查走索引的情况,特别是join查询、字查询、排序字段是否能走索引,如果没有走加上索引基本能解决问题
  2. 如果走了索引,则看是否能减少查询,让SQL不会表走索引覆盖或索引下推的逻辑
  3. 如果是join,或者某些子查询会自动优化为join的,如果MySQL所在机器内存够,可以增加join buffer的大小
  4. 如果是order by慢,那么也可以调整sort buffer的大小
  5. 如果还是慢,那就看是否是返回的数据确实太多了,是不是可以改成分页,这就需要修改应用层的代码了
  6. 如果还是慢,那肯定就是表中的数据确实太多了,那就看是不是能把一些数据进行归档,减少当前表的数据量
  7. 如果还是慢,那就要考虑分库分表,或者一些分布式数据库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2092790.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

fastmock使用

FastMock 是一个在线工具,用于快速创建和管理模拟 API(Mock API)。它主要用于前端开发,允许开发者在没有真实后端服务的情况下,模拟 API 响应,从而加速开发和测试过程。 FastMock网址:fastmock.…

Java多进程调用dll程序和exe程序

🎯导读:本文介绍了使用Java调用本地DLL及EXE程序的方法。针对DLL调用,文章提供了基于Java Native Access (JNA) 库的具体实现方案,包括定义Java接口以映射DLL中的函数,并展示了如何加载DLL及调用其中的方法。对于EXE程…

Python 数据可视化:工具与实践

文章目录 数据可视化可视化库特点对比实例:绘制基本数据分布图评估维度 交互式可视化与静态图表实例:创建交互式折线图评估维度 实时数据可视化实例:展示实时股票数据评估维度 图表设计原则实例:设计适合展示销售数据的条形图评估…

论文辅助笔记:LP_BERT

1 train_task1.py 1.1 main部分 读取命令行参数,调用task1函数 1.2 task1 train 1.3 task1 valid 1.3 collate_fn 2 Dataset 2.1 train dataset 2.2 valid dataset 3 LPBERT 3.1 不同的embedding day-of-week embedding和time-of-day embedding X位置和Y位置的…

色彩与笔触的交响:广州米塔在线科教技术有限公司揭秘PS绘画秘籍!

在数字艺术的广阔天地里,PS无疑是一颗璀璨的明星,它不仅在图像处理领域独领风骚,更以其强大的功能成为了众多艺术家和设计师进行数字绘画的首选工具。广州米塔在线科教技术有限公司,作为致力于艺术教育与技术分享的平台,深知掌握P…

sealos快速搭建k8s集群

一,环境准备 1,三台(搭建一主两从集群)或五台(三主两从集群)虚拟机, 安装alimaLinux系统 ,相同的root密码,不要安装docker。 如果是alimaLinux-mini版本操作系统&#xf…

PMP–知识卡片--SCQA金字塔表达

SCQA模型通过四个关键元素:情景冲突疑问答案,建立了一个精确而有逻辑的表达框架。同时,它也能够帮助你构建合理的逻辑链条,让别人更容易理解和接受你的观点。 情景:通过描述背景和现状引入话题,这个元素帮助…

两个月冲刺软考——关系模式中的候选关键字与如何分解为无损连接并保持函数依赖的解法(例题讲解,看完必会)

1. 数据库中的简单属性、多值属性、复合属性、派生属性 简单属性:指不能够再分解成更小部分的属性,通常是数据表中的一个列。例如学生表中的“学号”、“姓名”等均为简单属性。 多值属性:指一个属性可以有多个值。例如一个学生可能会有多个…

掌握EF Core:全方位面试指南,助你从初级到高级轻松晋级

一、前言 这份指南旨在帮助你为主要考察 Entity Framework Core (EF Core) 的面试做好准备,内容涵盖基础、中级和高级三个不同经验级别。每个级别包括10个高频面试题,附有解题思路和详细的解答示例。 二、基础级别 重点在于 EF Core 的基本概念和使用…

nginx源码编译

华子目录 准备下载nginx源码包关闭firewalld和selinux安装依赖环境 安装解压关闭nginx的debug功能执行./configure进行环境检测添加nginx系统用户使用make编译使用make install安装 进入到prefix指定的目录中查看启动nginx服务关闭nginx添加nginx环境变量卸载nginx 准备 下载n…

猫头虎 分享:Python库 SciPy 的简介、安装、用法详解入门教程

🐯 猫头虎 分享:Python库 SciPy 的简介、安装、用法详解入门教程 今天猫头虎带您深入探索SciPy,一个在数据科学和人工智能领域必不可少的Python库! 📝 摘要 在数据科学和人工智能领域,SciPy 是一个关键的…

【电脑小白】告别蓝屏恐慌:一步步教你排查和解决蓝屏问题,从此告别蓝屏烦恼!

在日常学习和工作中,电脑已经成为我们日常生活和工作中不可或缺的一部分。然而,电脑的蓝屏问题却成为许多朋友,尤其是电脑小白们的噩梦。一旦遭遇蓝屏,大多数人一时都会感到手足无措。 因此,本文将向各位朋友介绍遇到蓝…

迁移学习之领域泛化

对目标领域一无所知,并不是要适应到某一个特定的领域上的问题通常称为领域泛化。领 域泛化可又分成两种情况。一种情况是训练数据非常丰富,包含了各种不同的领域,测试数据 只有一个领域。如图1(a)所示,比如…

2024年8月30日(docker部署project-exam-system系统 并用Dockerfile构建java镜像)

一、回顾 1.使用harbao仓库 1. Python -- version 2. yum -y update 3. yum -y install python2-pip 4. pip install -- upgrade pip 20.3 -i https://mirrors.aliyun.com/pypi/simple 5. pip install docker-compose -i https://mirrors.aliyun.com/pypi/simple 6. source do…

向量、数量积、向量积

目录 一、向量的定义二、向量是有序的数字列表三、向量的基本分类四、向量的运算律五、向量的基本运算1、向量加法2、向量乘法(数乘)3、向量减法4、点积(内积或数量积)5、叉积(外积或向量积)6、向量的模&am…

RTA-OS Port Guide学习(一)-基于S32K324 OS

文章目录 前言OS Port的安装Port CharacteristicsParameters of ImplementationConfiguration ParametersStack used for C-startup(SpPreStartOS)Stack used when idle (SpStartOS)Stack overheads for ISR activation (SpIDisp)Stack overheads for ECC tasks (SpECC)Stack o…

LLM的范式转移:RL带来新的 Scaling Law

从几周前 Sam Altman 在 X 上发布草莓照片开始,整个行业都在期待 OpenAI 发布新模型。根据 The information 的报道,Strawberry 就是之前的 Q-star,其合成数据的方法会大幅提升 LLM 的智能推理能力,尤其体现在数学解题、解字谜、代…

<Rust>egui学习之小部件(三):如何为窗口UI元件设置布局(间隔、水平、垂直排列)?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析,主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统:windows 平台:visual studio code 语言:rust 库:egui、eframe 概述 本文是本专栏的第三篇博…

TWRP 使用帮助 第三方Recovery

简介 TWRP 是国外安卓爱好者开发的一款工具全称为:Team Win Recovery Project。是一个由Omnirom开源团队中的Dees Troy主导开发,旨在打造最完美第三方recovery的开源项目。目前主要由包括Dees Troy在内的4个人共同维护。 主要作用包括刷机、备份、救砖 …

C++判断语句(基础速通)ac-wing

倍数 #include <iostream> using namespace std; int a, b; int main() {cin >> a >> b;if (a % b 0 || b % a 0) cout << "Sao Multiplos";else cout << "Nao sao Multiplos";return 0; }零食 #include <iostream>…