常见面试题-MySQL专栏(二)

news2024/10/6 8:39:49

了解索引扫描吗?

答:

MySQL有两种方法生成有序结果:

  • 通过排序操作
  • 按照索引顺序扫描

如果 explain 出来的 type 列值为 “index” 的话,说明是按照索引扫描了。

索引扫描本身的速度是很快的。但是如果索引不能覆盖查询所需的全部列的话,那在每次查询索引时都需要回表再查询其他字段,这样的话,按索引顺序读取的速度通常比顺序地全表扫描要慢。如下图,select *时没有使用索引,select age时使用了索引。

explain select age from user order by age; # 结果1
explain select * from user order by age; # 结果2

请添加图片描述

设计:设计的时候,尽可能让同一个索引既满足排序,又用于查找行,这样是最好的。

只有当索引的列顺序和order by子句的顺序完全一致时,MySQL才能使用索引来对结果进行排序,如果查询需要关联多张表时,只有order by子句引用的字段全部为第一个表时,才能使用索引做排序。

order by查询时,需要满足索引的最左前缀要求,否则MySQL需要执行排序操作,无法利用索引进行排序。

order by有一种情况可以不满足索引的最左前缀的要求:前导列为常量。(即如果age,name为索引列,那么select * from user where age = 30 order by name,使用where将age指定为常量,这时也是可以使用索引排序的)

索引这么多优点,为什么不对表中的每一个列创建一个索引呢?使用索引一定提高查询性能吗?

答:

如果出现过多的重复索引和未使用索引,会影响插入、删除、更新的性能。

例如,如果创建了一个主键id,再去向id上添加索引,那么就添加了重复的索引,因为MySQL的主键限制也是通过索引实现的。

冗余索引是:如果创建了索引(A, B),再创建索引(A)就是冗余索引,因为(A)是(A, B)的前缀索引。

还有一种情况是,(A, ID)其中ID是主键,也是冗余索引,因为在 InnoDB 中,二级索引的叶子节点中已经包含主键值了。

使用索引一定提高查询性能吗?

不一定

  • 在数据量比较小的表中,使用全表扫描比使用索引扫描速度更快,并且可以直接获取到全量数据
  • 索引虽然提高了查询性能,但是在插入、删除、更新的过程中也是需要进行维护的

最左前缀匹配原则?

答:

最左前缀原则:规定了联合索引在何种查询中才能生效。

规则如下:

  • 如果想使用联合索引,联合索引的最左边的列必须作为过滤条件,否则联合索引不生效

如下图:

请添加图片描述

 假如索引为:(name, age, position)
select * from employee where name = 'Bill' and age = 31;
select * from employee where age = 30 and position = 'dev';
select * from employee where position = 'manager';

对于上边三条 sql 语句,只有第一条 sql 语句走了联合索引。

为什么联合索引需要遵循最左前缀原则呢?

因为索引的排序是根据第一个索引、第二个索引依次排序的,假如我们单独使用第二个索引 age 而不使用第一个索引 name 的话,我们去查询age为30的数据,会发现age为30的数据散落在链表中,并不是有序的,所以使用联合索引需要遵循最左前缀原则。

索引下推?

答:

在索引遍历过程中,对索引中包含的所有字段先做判断,过滤掉不符合条件的记录之后再回表,可以有效减少回表次数

比如:

索引:(name, age, positioni)
SELECT * FROM employees WHERE name like 'LiLei%' AND age = 22 AND position ='manager';

对上面这条 sql 语句就是用了索引下推,经过索引下推优化后,在联合索引(name,age,position)中,匹配到名字是 LiLei 开头的索引之后,同时还会在索引中过滤 age、position 两个字段的值是否符合,最后会拿着过滤完剩下的索引对应的主键进行回表,查询完整数据

(MySQL5.6 之前没有索引下推,因此匹配到 name 为 LiLei 开头的索引之后,会直接拿到主键,进行回表查询)

优点:

  • 索引下推可以有效减少回表次数
  • 对于 InnoDB 引擎的表,索引下推只能用于二级索引,因为 InnoDB 的主键索引的叶子节点存储的是全行数据,如果在主键索引上使用索引下推并不会减少回表次数

MySQL 的锁

答:

MySQL 的锁

从数据操作的粒度分的话,分为表锁和行锁

从数据操作的类型分的话,分为读锁和写锁

表锁

每次操作锁住整张表,锁粒度大,性能低

  • 手动增加表锁(可以给表加读锁或写锁,如果加读锁,其他会话可以读,但是无法写;如果加写锁。其他会话的读写都会被阻塞)

lock table 表名 read(write)

  • 查看表上加过的锁

show open tables;

  • 删除表锁

unlock tables;

行锁

每次操作锁住一行数据,锁力度小,性能高

InnoDB与MYISAM的最大不同有两点:

  • InnoDB支持事务
  • InnoDB支持行级锁

总结

  • MyISAM 在执行查询语句 select 前,会自动给涉及的所有表加读锁,在执行 update、insert、delete 操作会自动给涉及的表加写锁。

  • InnoDB 在执行查询语句 select 时(非串行隔离级别),不会加锁。但是 update、insert、delete 操作会加行锁。

  • 简而言之,就是读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞。

  • 锁主要是加在索引上,如果对非索引字段更新,行锁可能会变表锁:
    假如 account 表有 3 个字段(id, name, balance),我们在 name、balance 字段上并没有设置索引
    session1 执行:

     mysql> begin;
     Query OK, 0 rows affected (0.00 sec)
     
     mysql> select * from account;
     +----+------+---------+
     | id | name | balance |
     +----+------+---------+
     |  1 | zs   |     777 |
     |  2 | ls   |     800 |
     |  3 | ww   |     777 |
     |  4 | abc  |     999 |
     | 10 | zzz  |    2000 |
     | 20 | mc   |    1500 |
     +----+------+---------+
     6 rows in set (0.01 sec)
     
     mysql> update account set balance = 666 where name='zs';
     Query OK, 1 row affected (0.00 sec)
     Rows matched: 1  Changed: 1  Warnings: 0
    

    此时 session2 执行(发现执行阻塞,经过一段时间后,返回结果锁等待超时,证明 session1 在没有索引的字段上加锁,导致行锁升级为表锁,因此 session2 无法对表中其他数据做修改):

     mysql> begin;
     Query OK, 0 rows affected (0.00 sec)
     
     mysql> update account set balance = 111 where name='abc';
     RROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
    

    InnoDB 的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则会从行锁升级为表锁

select for update 了解吗?

答:

select for update 即排他锁,根据 where 条件的不同,对数据加的锁又分为行锁和表锁:

  • 如果 where 字段使用到了索引,则会添加行锁
  • 如果 where 字段没有使用索引,则会添加表锁

并发事务带来的问题

答:

  • 脏写:多个事务更新同一行,每个事务不知道其他事务的存在,最后的更新覆盖了其他事务所做的更新
  • 脏读:事务 A 读取到了事务 B 已经修改但是没有提交的数据,此时如果事务 B 回滚,事务 A 读取的则为脏数据
  • 不可重复读:事务 A 内部相同的查询语句在不同时刻读出的结果不一致,在事务 A 的两次相同的查询期间,有其他事务修改了数据并且提交了
  • 幻读:当事务 A 读取到了事务 B 提交的新增数据

不可重复读和幻读很类似,都是事务 A 读取到了事务 B 新提交的数据,区别为:

  • 不可重复读是读取了其他事务更改的数据,针对 update 操作
  • 幻读是读取了其他事务新增的数据,针对 insert 和 delete 操作

MySQL 的事务隔离级别了解吗?

答:

MySQL 的事务隔离级别分为:

  • 读未提交:事务 A 会读取到事务 B 更新但没有提交的数据。如果事务 B 回滚,事务 A 产生了脏读
  • 读已提交:事务 A 会读取到事务 B 更新且提交的数据。事务 A 在事务 B 提交前后两次查询结果不同,产生不可重复读
  • 可重复读:保证事务 A 中多次查询数据一致。可重复读是 MySQL 的默认事务隔离级别。可重复读可能会造成幻读 ,事务A进行了多次查询,但是事务B在事务A查询过程中新增了数据,事务A虽然查询不到事务B中的数据,但是可以对事务B中的数据进行更新
    演示可重复读:
    1. 先创建一个事务 A,查询表

       mysql> start transaction;
       Query OK, 0 rows affected (0.00 sec)
       
       mysql> select * from account;
       +----+------+---------+
       | id | name | balance |
       +----+------+---------+
       |  1 | zs   |     150 |
       |  2 | ls   |     200 |
       +----+------+---------+
       2 rows in set (0.00 sec)
      
    2. 此时再去创建事务 B,修改数据让第一条数据的 balance 减去 50,并且提交事务

       mysql> start transaction;
       Query OK, 0 rows affected (0.00 sec)
       
       mysql> update account set balance = balance - 50 where id = 1;
       Query OK, 1 row affected (0.00 sec)
       Rows matched: 1  Changed: 1  Warnings: 0
       
       mysql> select * from account;
       +----+------+---------+
       | id | name | balance |
       +----+------+---------+
       |  1 | zs   |     100 |
       |  2 | ls   |     200 |
       +----+------+---------+
       2 rows in set (0.00 sec)
       
       mysql> commit;
       Query OK, 0 rows affected (0.00 sec)
      
    3. 在事务 B 提交之后,在事务 A 中查询数据,发现与上次查询数据一致(可重复读)

       mysql> select * from account;
       +----+------+---------+
       | id | name | balance |
       +----+------+---------+
       |  1 | zs   |     150 |
       |  2 | ls   |     200 |
       +----+------+---------+
       2 rows in set (0.00 sec)
       ```
      
    4. 在事务 A 中让第一条数据的 balance 减去 50,由于在事务 B 中已经减去 1 次 50 了,所以在事务 A 中的 update account set balance = balance - 50 where id = 1 语句中的 balance 值使用的是上边步骤 2 中的 100,所以事务 A 中更新之后的 balance 值为 50。可重复读的隔离级别下使用了 MVCC 机制,select 操作不会更新版本号,是快照读(历史版本);insert、update 和 delete 会更新版本号,是当前读(当前版本)

       mysql> select * from account;
       +----+------+---------+
       | id | name | balance |
       +----+------+---------+
       |  1 | zs   |     150 |
       |  2 | ls   |     200 |
       +----+------+---------+
       2 rows in set (0.01 sec)
       
       mysql> update account set balance = balance - 50 where id = 1;
       Query OK, 1 row affected (0.00 sec)
       Rows matched: 1  Changed: 1  Warnings: 0
       
       mysql> select * from account;
       +----+------+---------+
       | id | name | balance |
       +----+------+---------+
       |  1 | zs   |      50 |
       |  2 | ls   |     200 |
       +----+------+---------+
       2 rows in set (0.00 sec)
      
    5. 验证出现幻读,重新打开事务 B,插入一条数据

       mysql> start transaction;
       Query OK, 0 rows affected (0.00 sec)
       
       mysql> select * from account;
       +----+------+---------+
       | id | name | balance |
       +----+------+---------+
       |  1 | zs   |      50 |
       |  2 | ls   |     200 |
       +----+------+---------+
       2 rows in set (0.00 sec)
       
       mysql> insert into account values(4, 'abc', 300);
       Query OK, 1 row affected (0.00 sec)
       mysql> select * from account;
       +----+------+---------+
       | id | name | balance |
       +----+------+---------+
       |  1 | zs   |      50 |
       |  2 | ls   |     200 |
       |  4 | abc  |     300 |
       +----+------+---------+
       3 rows in set (0.00 sec)
       
       mysql> commit;
       Query OK, 0 rows affected (0.01 sec)
      
    6. 在事务 A 中查询,发现没有看到事务 B 新插入的数据,但是事务 A 可以直接更新事务 B 中插入的数据(说明事务 A 是可以感知到事务 B 插入的数据,因此发生了幻读),更新之后,事务 A 再次查询就查询到了事务 B 的数据。

       mysql> select * from account;
       +----+------+---------+
       | id | name | balance |
       +----+------+---------+
       |  1 | zs   |      50 |
       |  2 | ls   |     200 |
       +----+------+---------+
       2 rows in set (0.00 sec)
       
       mysql> update account set balance = 888 where id = 4;
       Query OK, 1 row affected (0.00 sec)
       Rows matched: 1  Changed: 1  Warnings: 0
       
       mysql> select * from account;
       +----+------+---------+
       | id | name | balance |
       +----+------+---------+
       |  1 | zs   |      50 |
       |  2 | ls   |     200 |
       |  4 | abc  |     888 |
       +----+------+---------+
       3 rows in set (0.00 sec)
      
  • 可串行化:并发性能低,不常使用

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

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

相关文章

【每日一题】H 指数 II

文章目录 Tag题目来源题目解读解题思路方法一:二分查找 写在最后 Tag 【二分查找】【数组】【2023-10-30】 题目来源 275. H 指数 II 题目解读 本题与 274. H 指数 题目一致,只是加强了一下条件,数组是有序的。 解题思路 方法一&#xff…

【Docker】如何查看之前docker run命令启动的参数

个人主页:金鳞踏雨 个人简介:大家好,我是金鳞,一个初出茅庐的Java小白 目前状况:22届普通本科毕业生,几经波折了,现在任职于一家国内大型知名日化公司,从事Java开发工作 我的博客&am…

如何高效制作视频滚动字幕:批量剪辑攻略

在视频制作过程中,添加滚动字幕是常见且重要的环节。它不仅可以帮助传达信息,还能增强视频的观感体验。然而,对于需要大量制作字幕的视频,逐一添加字幕无疑会浪费大量时间和精力。因此,本文将为你介绍运用云炫AI智剪制…

1.让数组动起来

概述 对数组进行分析,目标如下 线性表的概念数组的存储结构数组查询,插入,删除操作的特点及对应的时间复杂度刷题(盛最多水的容器) 线性表 在数据结构中,数据的逻辑结构分为线性结构和非线性结构 线性结构: n个数据元素有序集合…

在 Visual Studio 中远程调试 C++ 项目

目录 一、说明二、下载远程工具1. 官网下载2. 自己电脑上拷贝 三、 运行远程工具四、本机Visual Studio配置五、自动部署 一、说明 参考官方文档:https://learn.microsoft.com/zh-cn/visualstudio/debugger/remote-debugging-cpp?viewvs-2022 二、下载远程工具 …

【C语言】calloc()函数详解(动态内存开辟函数)

🦄个人主页:修修修也 🎏所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 一.calloc()函数简介 我们先来看一下cplusplus.com - The C Resources Network网站上calloc()函数的基本信息: 1.函数功能 可以看到,calloc()函数的功能是:为num个大…

FastAPI框架学习笔记(快速入门FastAPI框架)

1. 写在前面 今天整理一篇后端框架的笔记, fastapi框架是比较主流的后端异步web框架,关键是python语言可以写,正好公司最近安排了一些后端服务的活, 所以就看了一个fastapi框架的入门课程(链接在底部),完成任务&#…

用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程

🧸注:不要看我的文件多,那是我的其他项目,这个项目所用的文件我会全部用红框框起来,没框的部分不用管,前端两个文件,后端一个文件 📜 目录 首先,定义前后端交互接口 然…

电子器件 电感

拿一根导线在笔上绕几圈,取下来就是一个空心电感,如果拿一个铁芯,在铁芯上绕相同的圈数,加了的铁芯的电感量是没有加铁芯的几千倍甚至上万倍,所以电感一般是有铁芯的。 下图是电感的模型,L 是理想电感&…

招生报名缴费小程序开发笔记(上)

前期调研 1.数字化趋势: 随着社会的数字化转型,越来越多的教育机构倾向于采用数字工具来简化和优化他们的招生和报名过程。招生报名缴费小程序是应对这一趋势的一种解决方案,可以提供高效、方便、快速的在线招生渠道。2.用户需求&#xff1a…

强化学习中值函数应用示例

一、Gridworld Gridworld是一个用于教授强化学习概念的简化的电子游戏环境。它具有一个简单的二维网格,智能体可以在其中执行动作并获得奖励。这个环境是有限的,因为它有一个明确的开始和结束状态,以及一组确定的动作和奖励。 在Gridworld中&…

C++二分查找算法的应用:最长递增子序列

涉及知识点 二分查找 单调映射 源码下载 点击下载源码 题目 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如&#xf…

Rust 语言介绍及安装

目录 1、简介 1.1 为什么选择Rust 高性能 可靠性 生产力 1.2 用 Rust 构建应用 命令行 WebAssembly 网络 嵌入式 2、安装 Rust Windows 的 Linux 子系统(WSL) 检查Rust 是最新的 卸载Rust版本: Cargo:Rust 的构建工…

读图数据库实战笔记03_遍历

1. Gremlin Server只将数据存储在内存中 1.1. 如果停止Gremlin Server,将丢失数据库里的所有数据 2. 概念 2.1. 遍历(动词) 2.1.1. 当在图数据库中导航时,从顶点到边或从边到顶点的移动过程 2.1.2. 类似于在关系数据库中的查…

我在Vscode学OpenCV 初步接触

OpenCV是一个开源的计算机视觉库,可以处理图像和视频数据。它包含了超过2500个优化过的算法,用于对图像和视频进行处理,包括目标识别、面部识别、运动跟踪、立体视觉等。OpenCV支持多种编程语言,包括C、Python、Java等&#xff0c…

光谱图像论文浅读

文章目录 Hyperspectral Image Super-Resolution via Deep Spatiospectral Attention Convolutional Neural Networks Hyperspectral Image Super-Resolution via Deep Spatiospectral Attention Convolutional Neural Networks 通过上采样高光谱保留其光谱特征,采用…

在R中安装CmdStanR的步骤-R4.3.1-CmdStanR-0.6.1.900

报错未安装cmdstanr 安装包官网详细介绍: R Interface to CmdStan • cmdstanrhttps://mc-stan.org/cmdstanr/ 以下是在R中安装CmdStanR的步骤: 1. 首先,需要下载和安装C编译器 例如gcc。如果您已经安装了C编译器,则可以跳过此…

【数据结构--C语言】有序表算法及其应用

有序表是指其中的所有元素以递增或递减方式有序排列。为了简单,假设有序表以递增排列。 有序表的基本运算 InitLIst(&L):初始化有序表LDestoryList(&L):销毁有序表LListEmpty(L):判断空表ListLength(L):求有…

Mysql进阶-索引篇(上)

目录 索引概述 索引结构 数据结构 二叉树 红黑树 B-Tree BTree Hash 索引分类 聚集索引&二级索引 聚集索引选取规则: 具体结构 索引基础语法 SQL性能分析 SQL执行频率 慢查询日志 profile详情 explain 索引概述 介绍: 索引( index &…

基于哈里斯鹰算法的无人机航迹规划-附代码

基于哈里斯鹰算法的无人机航迹规划 文章目录 基于哈里斯鹰算法的无人机航迹规划1.哈里斯鹰搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要:本文主要介绍利用哈里斯鹰算法来优化无人机航迹规划。 …