重启人生计划-拒绝内耗
🥳🥳🥳 茫茫人海千千万万,感谢这一刻你看到了我的文章,感谢观赏,大家好呀,我是最爱吃鱼罐头,大家可以叫鱼罐头呦~🥳🥳🥳
如果你觉得这个【重启人生计划】对你也有一定的帮助,加入本专栏,开启新的训练计划,漫长成长路,千锤百炼,终飞升巅峰!无水文,不废话,唯有日以继日,终踏顶峰! ✨✨欢迎订阅本专栏✨✨
❤️❤️❤️ 最后,希望我的这篇文章能对你的有所帮助! 愿自己还有你在未来的日子,保持学习,保持进步,保持热爱,奔赴山海! ❤️❤️❤️
🔥【重启人生计划】第零章序·大梦初醒🔥
🔥【重启人生计划】第壹章序·明确目标🔥
🔥【重启人生计划】第贰章序·勇敢者先行🔥
序言
大家好,我是最爱吃鱼罐头,距离离职已经过去一个月了,目前进度为2,打算重新找工作倒计时28天,当然这其中也会去投递面试。
山野万万里,人生路漫漫,日暮酒杯淡饭,一半一半,一半是山川湖海,一半是人间烟火。
今日回顾
真正执行计划时,才发现时间其实过得很快,我也想抓紧时间去努力提升自己,但我感觉焦虑已经悄然而生。这几天都看了招聘的,发现也还有很多公司都在招人,但我知道,机会毕竟有限。以前去面试的时候,其实心里或多或少带着有底气的心里,现在其实没有后路可言。我只能不断抓紧时间去提升自己,抓住每一次机会。人生的不如意,对每个人的当下来说,都是最好的安排。最后还是得拒绝焦虑,拒绝内耗,随遇而安。
挑战之旅第二天,今天早上大概回顾了下jvm的内容,后面就刷day3的算法题,难度简单,稍微想一下还是可以快速做出来的,下午就继续刷了jvm的面试题,明天开始算法和面试题都进入新的阶段。今晚的时间,会去看看链表的视频。
算法回顾
删除有序数组中的重复项 📍
删除有序数组中的重复项 📍

对于这道题的讲解呢,核心的关键在于双指针:
双指针的核心思想是通过使用两个指针在数组中进行遍历,从而达到相应的目的。
最常见的双指针算法的应用有:
- 对撞指针:两个指针分别从数据结构的两端向中间移动,通常用于解决排序数组中寻找某些特定的对或条件问题。例如,找到数组中和为目标值的两个数。
- 快慢指针:通常用于链表相关问题,如检测链表是否有环、找到链表的中间节点等。一个指针每次移动一步,另一个指针每次移动两步。
- 滑动窗口:一个指针表示窗口的开始位置,另一个指针表示窗口的结束位置。这个技术可以用于处理子数组或子串的相关问题,比如计算最大/最小值、找到符合条件的最长子串等。
而双指针的关键在于:
- 指针的起始位置的选取
- 指针的移动方向
- 指针的移动速度
而在昨天的二分查找📍题目中,其实也有双指针的影子,它就是对撞指针的实际应用。下面的几道就是相关快慢指针和滑动窗口的简单应用。
代码实现:
package com.ygt.day3;/*** 26. 删除有序数组中的重复项* https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/* 给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。* 考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:* 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。* 返回 k 。* 判题标准:* 系统会用下面的代码来测试你的题解:* int[] nums = [...]; // 输入数组* int[] expectedNums = [...]; // 长度正确的期望答案* int k = removeDuplicates(nums); // 调用* assert k == expectedNums.length;* for (int i = 0; i < k; i++) {* assert nums[i] == expectedNums[i];* }* 如果所有断言都通过,那么您的题解将被 通过。* 输入:nums = [0,0,1,1,1,2,2,3,3,4]* 输出:5, nums = [0,1,2,3,4]* 解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。* @author ygt* @since 2024/8/13*/
public class RemoveDuplicates {public static void main(String[] args) {int[] nums = {0,0,1,1,1,2,2,3,3,4};System.out.println("删除有序数组中的重复项的答案:" + new RemoveDuplicates().removeDuplicates(nums));}/*主要解题思路:需要掌握双指针*/public int removeDuplicates(int[] nums) {// 需要注意的一点是,"原地" 即在原数组上操作 --> 所以不能创建一个新数组/*这道题的思路:在于双指针的使用,顾名思义,需要两个指针,通过两个指针不断比较,移动指针实现目的。定义两个指针:fast:快指针 slow:慢指针开始比较,发现0=0 ,并且f向前移动 第二次开始比较,0!=1,s移动一位,并替换为1一开始的数组 --> 移动后的数组 --> 移动后的数组[ 0, 0, 1, 1, 2, 3] [ 0, 0, 1, 1, 2, 3] [ 0, 1, 1, 1, 2, 3]s f s f s f第三次开始比较,f一直移动到2处,1!=2,s移动一位,并替换为2 第四次开始比较,f移动到3处,2!=3,s移动一位,并替换为3--> 移动后的数组 --> 移动后的数组 --> 移动后的数组[ 0, 1, 1, 1, 2, 3] [ 0, 1, 2, 1, 2, 3] [ 0, 1, 2, 3, 2, 3]s f s f s f最后f到达数组末尾,结束*/int slow = 0, fast = 1;// fast只能移动到数组末尾处while (fast < nums.length) {if(nums[fast] != nums[slow]) {nums[++slow] = nums[fast];}fast++;}// 可以看一下当前数组 --> 可以看到前面正常改成功了,slow后面的是不管的。//System.out.println(Arrays.toString(nums));// 最终长度就是slow+1的大小return slow+1;}
}
移除元素 📍
移除元素 📍

对于这道题的讲解呢,也是双指针的快慢指针应用,而与上道题的区别,在于增加了一个val值,并且这道题跟顺序没大关系,只要是等于val的元素,就可以排除掉。
代码实现:
package com.ygt.day3;/*** 27. 移除元素* 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。* 假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:* 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。* 返回 k。* 用户评测:* 评测机将使用以下代码测试您的解决方案:* int[] nums = [...]; // 输入数组* int val = ...; // 要移除的值* int[] expectedNums = [...]; // 长度正确的预期答案。* // 它以不等于 val 的值排序。* int k = removeElement(nums, val); // 调用你的实现* assert k == expectedNums.length;* sort(nums, 0, k); // 排序 nums 的前 k 个元素* for (int i = 0; i < actualLength; i++) {* assert nums[i] == expectedNums[i];* }* 如果所有的断言都通过,你的解决方案将会 通过。* 输入:nums = [0,1,2,2,3,0,4,2], val = 2* 输出:5, nums = [0,1,4,0,3,_,_,_]* 解释:你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。* 注意这五个元素可以任意顺序返回。* 你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。* @author ygt* @since 2024/8/13*/
public class RemoveElement {public static void main(String[] args) {int[] nums = {0,1,2,2,3,0,4,2};System.out.println("移除元素得到的答案:" + new RemoveElement().removeElement(nums, 2));}/*主要解题思路:需要掌握双指针*/public int removeElement(int[] nums, int val) {// 需要注意的一点是,"原地" 即在原数组上操作 --> 所以不能创建一个新数组///*首先,实现的关键还是双指针,其次这道题跟前面一道题的区别:增加了一个val值,这道题跟顺序没大关系,只要是等于val的元素,就可以排除掉,而且返回的数组元素是无序。移动过程中,只要不是等于val值,s的替换为f的值。比较,f继续移动,直到遇到val值 f开始移动,直到遇到不是val值,s替换后并移动一开始的数组 --> 移动后的数组 --> 移动后的数组[ 0,1,2,2,3,0,4,2] [ 0,1,2,2,3,0,4,2] [0,1,3,2,3,0,4,2]s s s ff f一直移动,s不断替换,直到遇到2 但是到数组末尾了,不需要再替换了,结束--> 移动后的数组 --> 移动后的数组[0,1,3,0,4,0,4,2] [0,1,3,0,4,0,4,2]s f s f*/int slow = 0, fast = 0;// fast只能移动到数组末尾处while (fast < nums.length) {if(nums[fast] != val) {nums[slow++] = nums[fast];}fast++;}// 可以看一下当前数组 --> 可以看到前面正常改成功了,slow后面的是不管的。//System.out.println(Arrays.toString(nums));// 最终长度就是slow的大小 --> 这里不需要加一了,因为slow有自动加一。return slow;}
}
有序数组的平方
有序数组的平方📍

对于这道题的讲解呢,是双指针的对撞指针应用。
代码实现:
package com.ygt.day3;import java.util.Arrays;/*** 977. 有序数组的平方* https://leetcode.cn/problems/squares-of-a-sorted-array/description/* 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。* 输入:nums = [-4,-1,0,3,10]* 输出:[0,1,9,16,100]* 解释:平方后,数组变为 [16,1,0,9,100]* 排序后,数组变为 [0,1,9,16,100]* @author ygt* @since 2024/8/13*/
public class SortedSquares {public static void main(String[] args) {int[] nums = {-4,-1,0,3,10};System.out.println("有序数组的平方的答案:" + Arrays.toString(new SortedSquares().sortedSquares(nums)));}/*主要解题思路:需要掌握双指针*/public int[] sortedSquares(int[] nums) {// 需要注意的一点是,原先为负数的值,平方后,可能反而变大。// 实现的关键还是双指针, 实现思路:前后比较,从后不断填充大的值。int left = 0, right = nums.length - 1;// 需要一个新数组来实现,不断填充数据。int[] result = new int[nums.length];int resultIndex = right;while (left <= right){int leftValue = nums[left] * nums[left];int rightValue = nums[right] * nums[right];// 比较大小,谁大,填充谁的数据,并移动指针。if(leftValue > rightValue) {result[resultIndex] = leftValue;left ++;}else {result[resultIndex] = rightValue;right --;}resultIndex --;}return result;}
}
最长连续递增序列
最长连续递增序列📍

对于这道题的讲解呢,是双指针的滑动窗口应用。
滑动窗口的基本思想是用一个窗口(通常是一个固定大小的区间)在数组上滑动,通过维护这个窗口内的状态来解决问题。
滑动窗口的基本操作
- 初始化:设定窗口的初始位置,通常是数组的开始位置或数据流的开始位置;
- 扩展:逐步扩大窗口的范围,直到达到一定条件或者窗口的右边界;
- 收缩:当需要缩小窗口时,移动窗口的左边界,直到满足特定条件。
代码实现:
package com.ygt.day3;/*** 674. 最长连续递增序列* https://leetcode.cn/problems/longest-continuous-increasing-subsequence/description/* 给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。* 连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,* 那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。* 输入:nums = [1,3,5,4,7]* 输出:3* 解释:最长连续递增序列是 [1,3,5], 长度为3。* 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。** @author ygt* @since 2024/8/13*/
public class FindLengthOfLCIS {public static void main(String[] args) {int[] nums = {1, 3, 5, 4, 7};System.out.println("最长连续递增序列的答案:" + new FindLengthOfLCIS().findLengthOfLCIS(nums));}/*主要解题思路:需要掌握双指针和滑动窗口*/public int findLengthOfLCIS(int[] nums) {// 滑动窗口的思想就是双指针,根据需要不断扩大指针,从而达到一个窗口的目的。/*f一直移动到4,最大为3 s重新替换为4处,f一直移动到7,最大为2[1,3,5,4,7] [1,3,5,4,7] [1,3,5,4,7]s s sf f f所以最终最大为3*/int slow = 0 , fast = 1, max = 1;while (fast < nums.length) {// fast只要是比前面位置小或者相等,就不是递增序列,可以判断当前的最长连续递增序列if(nums[fast-1] >= nums[fast]){slow = fast;}fast++;max = Math.max(max, (fast - slow));}return max;}
}
最大连续 1 的个数
最大连续 1 的个数📍

对于这道题的讲解呢,万变不离其宗,也是双指针的滑动窗口应用。
代码实现:
package com.ygt.day3;/*** 485. 最大连续 1 的个数* https://leetcode.cn/problems/max-consecutive-ones/description/* 给定一个二进制数组 nums , 计算其中最大连续 1 的个数。* 输入:nums = [1,1,0,1,1,1]* 输出:3* 解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.* @author ygt* @since 2024/8/13*/
public class FindMaxConsecutiveOnes {public static void main(String[] args) {int[] nums = {1,1,0,1,1,1};System.out.println("最大连续 1 的个数的答案:" + new FindMaxConsecutiveOnes().findMaxConsecutiveOnes(nums));}/*主要解题思路:需要掌握双指针和滑动窗口*/public int findMaxConsecutiveOnes(int[] nums) {// 滑动窗口的思想就是双指针,根据需要不断扩大指针,从而达到一个窗口的目的。// 这道题的思路,跟上一道一样类似,无非就是判断条件改了而已,判断不等于1而已。int slow = 0, fast = 0, max = 0;while (fast < nums.length) {if(nums[fast] != 1) {slow = fast + 1;}fast++;max = Math.max(max, (fast - slow));}return max;}
}
小结算法
今天的算法还是相对比较简单,很好刷,认真思考下,就可以完成的。

明日内容
基础面试题
下面的题目的答案是基于自己的理解和思考去编写出来的,也希望大家如果看到了,可以根据自己的理解去转换为自己的答案。
当然很多思考也有参考别人的成分,但是自己能讲述出来就是最棒的。
这里有一篇阿里的mysql面试题

明天给自己的目标是,二倍速过一下mysql的视频,能过多少算多少。
1. 一条SQL的执行过程是怎样的?
- 连接器:
- 客户端与数据库建立连接,并发送 SQL 语句给数据库服务;
- 连接器验证客户端的身份和权限,确保用户有足够的权限执行该 SQL 语句。
- 查询缓存:
- 连接器首先检查查询缓存,尝试找到与当前 SQL 语句完全相同的查询结果;
- 如果在缓存中找到匹配的结果,查询缓存直接返回结果,避免了后续的执行过程。
- 分析器:
- 若查询不命中缓存,连接器将 SQL 语句传递给分析器进行处理;
- 分析器对 SQL 语句进行语法分析,确保语句的结构和语法正确;
- 分析器还会进行语义分析,检查表、列、函数等对象的存在性和合法性,为其创建语法树,并根据数据字典丰富查询语法树,会验证该客户端是否具有执行该查询的权限。
- 优化器:
- 分析器将经过验证的 SQL 语句传递给优化器;
- 优化器对SQL 语句进行优化,包括不同的索引选择、连接顺序、筛选条件等,最后生成一条最优的执行计划。
- 执行器:
- 优化器选择一个最优的执行计划,并将其传递给执行器;
- 执行器根据执行计划执行具体的查询操作;
- 它负责调用存储引擎的接口,处理数据的存储、检索和修改;
- 执行器会根据执行计划从磁盘或内存中获取相关数据,并进行连接、过滤、排序等操作,生成最终的查询结果。
- 存储引擎:
- 执行器将查询请求发送给存储引擎组件;
- 存储引擎组件负责具体的数据存储、检索和修改操作;
- 存储引擎根据执行器的请求,从磁盘或内存中读取或写入相关数据。
- 返回结果:
- 存储引擎将查询结果返回给执行器。
- 执行器将结果返回给连接器。
- 最后,连接器将结果发送回客户端,完成整个执行过程。
最后,查询缓存在一些场景下可能不太适用,因为它有一定的缺陷和开销。MySQL 8.0 版本开始,默认情况下查询缓存已被废弃。因此,在实际应用中,需要权衡是否使用查询缓存。
2. 存储引擎Innodb结构
mysql的InnoDB存储引擎架构,包括了内存架构和磁盘架构两部分。
内存结构:
-
Buffer Pool:
- Buffer Pool(缓冲池)是主内存中的一部分空间,用来缓存已使用的表和索引数据;
- 当数据库操作数据的时候,把硬盘上的数据加载到buffer pool,不直接和硬盘打交道,操作的是buffer pool里面的数据;
- 数据库的增删改查都是在buffer pool上进行,和undo log、redo log、redo log buffer、binlog⼀起使用,后续会把数据刷到硬盘上,Buffer Pool的默认大小为128M。
-
Change Buffer:
- Change Buffer(修改缓冲区)是一个特殊的数据结构,用于缓存不在缓冲池中的那些二级索引页的变更。由insert, update或delete这些dml操作导致被缓存的变化,将在当这些页被其他读操作加载到缓冲池后合并。
-
Log Buffer:用来缓存redolog,Log Buffer会定期地将日志文件刷入磁盘。
-
Adaptive Hash Index:自适应哈希索引。
磁盘结构
-
系统表空间 系统表空间包括InnoDB数据字典、双写缓存、更新缓存和撤销日志,同时也包括表和索引数据。多表共享,系统表空间被视为共享表空间。
-
双写缓存 双写缓存位于系统表空间中,用于写入从缓存池刷新的数据页。只有在刷新并写入双写缓存后,InnoDB才会将数据页写入合适的位置。
-
撤销日志 撤销日志是一系列与事务相关的撤销记录的集合,包含如何撤销事务最近的更改。如果其他事务要查询原始数据,可以从撤销日志记录中追溯未更改的数据。撤销日志存在于撤销日志片段中,这些片段包含于回滚片段中。
-
每个表一个文件的表空间 每个表一个文件的表空间是指每个单独的表空间创建在自身的数据文件中,而不是系统表空间中。这个功能通过innodb_file_per_table配置项开启。每个表空间由一个单独的.ibd数据文件代表,该文件默认被创建在数据库目录中。
-
通用表空间 使用CREATE TABLESPACE语法创建共享的InnoDB表空间。通用表空间可以创建在MySQL数据目录之外能够管理多个表并支持所有行格式的表。
-
撤销表空间 撤销表空间由一个或多个包含撤销日志的文件组成。撤销表空间的数量由innodb_undo_tablespaces配置项配置
-
临时表空间 用户创建的临时表空间和基于磁盘的内部临时表都创建于临时表空间。innodb_temp_data_file_path配置项定义了相关的路径、名称、大小和属性。如果该值为空,默认会在innodb_data_home_dir变量指定的目录下创建一个自动扩展的数据文件
-
重做日志 重做日志是基于磁盘的数据结构,在崩溃恢复期间使用,用来纠正数据。正常操作期间,重做日志会将请求数据进行编码,这些请求会改变InnoDB表数据。遇到意外崩溃后,未完成的更改会自动在初始化期间重新进行。
3. MyISAM和InnoDB的区别?
- 存储方式:MyISAM使用非聚簇索引,索引文件和数据文件是分开的;而InnoDB使用聚簇索引,将索引和数据一起存储在同一个文件中。
- 外键约束:MyISAM不支持外键约束,而InnoDB支持外键约束,可以设置关联关系来保证数据的完整性。
- 锁机制:MyISAM采用表级锁定,意味着当对表进行写操作时,整个表都会被锁定,因此可能导致并发写操作的性能较差。而InnoDB采用行级锁定,只锁定需要修改的行,可以提供更好的并发性能和多用户写入的支持。
- 事务支持:MyISAM不支持事务处理,而InnoDB支持事务和ACID特性(原子性、一致性、隔离性和持久性),可以进行事务管理、回滚和恢复操作。
- 崩溃恢复:InnoDB具备崩溃恢复的能力,能够在数据库、服务器或系统发生故障时,恢复到崩溃前的状态。这是因为InnoDB引擎使用了redo日志和undo日志来记录数据的修改操作,确保数据的持久性。
- 性能特点:MyISAM在读取频繁、插入和更新较少的场景下性能较好,特别适合于读密集型应用;而InnoDB在并发写入和更新较多的情况下性能较好,适合于写入密集型应用或需要事务支持的场景。
以上就是MyISAM与InnoDB的区别,我们在实际使用时需要根据具体的应用需求和场景来选择适合的存储引擎和索引类型。
4. 索引的优缺点
索引是数据库中用于提高数据检索性能的排好序的数据结构。通过建立特定的数据结构将列或多个列的值与它们在数据表中对应的行关联起来,以加快查询速度。索引一般存储在磁盘的文件中,它是占用物理空间的。
✅ 索引的优点
- **提高查询性能:**索引可以加快数据库查找数据的速度,通过快速定位到符合查询条件的数据行,减少了数据库进行全表扫描的开销,从而显著提高查询效率;
- **唯一性约束:**通过在索引上设置唯一性约束,可以确保数据的唯一性,防止重复数据的插入;
- 加快表与表之间的连接:对于有依赖关系的子表和父表联合查询时,可以提高查询速度。
❌ 索引的缺点
- **占用存储空间:**索引通常需要占用一定的磁盘空间,过多的索引可能会增加存储成本;
- **索引维护的开销:**当对数据表进行插入、更新或删除操作时,索引也需要进行相应的维护操作,这可能导致数据写入的性能下降,更新缓慢。
5. Hash索引和B+树索引的区别?
索引的数据结构和具体的存储引擎实现有关,mysql默认存储引擎Innodb使用的默认索引是B+Tree索引,对于mysql使用较多也有hash索引。对于Hash索引来说,如果单条查询较多的话,可以使用hash索引,速度最快。而其他大部分场景就适合选择B+Tree索引。
-
B+Tree索引
B+Tree是一个平衡的多叉树,从根节点到每个叶子节点的高度差不会超过1,而且同层级的节点有指针相互连接,所以对于有一些范围查询的话,适合使用B+Tree索引,可以利用双向指针进行快速的左右移动,效率比较高,而对于常规查询的话,从根节点到叶子结点的搜索效率基本相同,不会相差太多。
-
Hash索引
哈希索引就是通过哈希算法计算成哈希值,然后存储在哈希表中,如果是单条等值查询的话,效率最高,因为只用计算一次哈希算法得到对应的哈希值就可以找到了,但是如果重复值较多的话,可能还需要在后续的链表中进行逐个查询,直到查询到为止。
对于范围查询的话,哈希算法非常不支持,因为它计算一次哈希算法,然后没办法快速的左右移动。
6. B 树和B+树的区别?
对于B树来说,非叶子结点同样存储数据,叶子结点中没有指向其他结点的指针;
对于B+树来说,非叶子结点不存储数据,只存储索引,叶子结点用指针相连,提高区间访问的性能。相比于B树,在相同深度下存放更多的索引,MySQL中千万级数据树高只需3层,并且支持范围查询。
B树适合随机读写操作,而B+树适合范围查询和顺序访问。在实际应用中,根据不同的场景和需求选择合适的树结构可以带来更高效的数据处理和索引操作。
7. 回表
回表操作发生于非聚簇索引查询时,需要查找完整的用户记录或者不包括当前索引的字段,就需要到聚簇索引中再查一遍,这个过程称为回表。
8. 覆盖索引
当一个查询需要返回的数据列都包含在一个或多个索引中时,就可以利用索引覆盖来避免额外的磁盘读取操作,从而提高查询性能。
所以如果索引能覆盖到查询的列,那么就可以避免对主键索引的二次查询。
9. 最左前缀法则(最左匹配)
最左前缀原则是数据库索引设计中的一个重要原则,当联合索引包含多个列时,查询语句可以利用从左到右的顺序使用索引,但只能连续使用最左侧的列来进行索引扫描。也就是说,如果一个查询只使用了联合索引中的部分列作为查询条件,那么只有从索引的最左侧列开始连续使用时,索引才会有效。
例如,假设有一个联合索引 (a, b, c),那么查询条件中包含 a 和 b 的查询可以利用该索引,而只包含 b 或者只包含 c 的查询则无法使用该索引。
遵循最左前缀原则的好处包括:
- **提高查询性能:**通过使用索引的最左前缀,可以最大限度地减少索引扫描的数据量,提高查询的效率和响应时间。
- **减少索引占用空间:**在某些情况下,使用最左前缀原则可以减少创建多个索引的需求,节省磁盘空间和索引维护的开销。
10. 索引失效情况
-
使用
like并且是左边带%, 右边可以带会走索引; -
隐式类型转换,索引字段与条件或关联字段的类型不一致;
-
在
where条件里面对索引列使用运算或者使用函数; -
使用
OR且存在非索引列; -
在
where条件中两列做比较会导致索引失效; -
使用IN可能不会走索引;
-
使用非主键范围条件查询时,部分情况索引失效 ;
-
使用
order by可能会导致索引失效; -
is nullis not null≠可能会导致索引失效。
11. Innodb的数据结构
InnoDB存储引擎将数据划分为若干个页,页的默认大小为16kb。以页作为磁盘和内存之间交互的基本单位,也就是一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。
各个数据页中通过双向链表管理,每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表,每个数据页都会为存储在它里边的记录生成一个页目录,在通过主键查找某条记录的时候可以在页目录中使用二分法快速定位到对应的页,然后再遍历该页对应分组中的记录即可快速找到指定的记录。
另外在数据库中,还存在区(Extent)、段(Segment)和表空间(Tablespace):
-
区是比页大一级的存储结构,在InnoDB存储引擎中,一个区会分配
64个连续的页。因为InnoDB中的页大小默认是16KB,所以一个区的大小是64*16KB= 1MB。 -
段由一个或多个区组成,区在文件系统是一个连续分配的空间(在InnoDB中是连续的64个页),不过在段中不要求区与区之间是相邻的。
段是数据库中的分配单位,不同类型的数据库对象以不同的段形式存在。当创建数据表、索引的时候,就会相应创建对应的段,比如创建一张表时会创建一个表段,创建一个索引时会创建一个索引段。 -
表空间是一个逻辑容器,表空间存储的对象是段,在一个表空间中可以有一个或多个段,但是一个段只能属于一个表空间。数据库由一个或多个表空间组成,表空间从管理上可以划分为系统表空间,
用户表空间、撤销表空间、临时表空间等。
页结构:
数据页的存储空间被划分为七个部分,分别是文件头(File Header)、页头(Page Header)、最大最小记录(Infimum+supremum)、用户记录(User Records)、空闲空间(Free Space)、页目录(Page Directory)和文件尾(File Tailer) 。
- 文件头:描述页的通用信息,主要包括有:页号、上一页、下一页、页的类型、校验和、日志序列号;
- 文件尾:校验页的完整性,主要包括有校验和和日志序列号;
- 空闲空间:页中还没有被使用的空间,随着记录不断插入,空闲空间不足时,就会申请新的页;
- 用户记录:按照指定的行格式一条一条存储,相互之间使用单链表关联;
- 最大最小记录:表示页中记录的最小和最大;
- 页目录:页内记录进行二分法分组,方便在一个页中二分查找进行检索,提升效率;
- 页头:主要包括有:页目录中槽数量、本页中的记录数量、第一个删除的记录地址、当前页中的层级等等。
行格式:
InnoDB存储引擎设计了4种不同类型的行格式,分别是Compact(紧密)、Redundant(冗余)、Dynamic(动态)和Compressed(压缩)行格式。
Compact:
- 变长字段长度列表:存储真实数据的实际长度大小,多个字段逆序存储;
- null指列表:把可以null的列统一管理,存在一个标记null值的列表中;
- 记录头信息:
- delete_mask:标记该记录是否被删除;
- min_rec_mask:B+树的每层非叶子结点的最小记录都会添加该标记;
- n_owned:表示当前记录拥有的记录数;
- heap_no:表示当前记录在本页的位置;
- record_type:表示当前记录的类型,0表示普通记录,1表示非叶子结点记录,2表示最小记录,3表示最小记录。
- next_record:表示下一条记录的偏移量。
- 隐藏列:
- db_row_id:行ID;
- db_trx_id:事务ID;
- db_roll_ptr:回滚指针。
算法
在有链表的基础上进行链表的算法题,可以事半功倍。

需要有链表以及双指针的基础。
- 设计链表 📍
- 删除链表中的节点📍
- 反转链表 📍
- 删除排序链表中的重复元素 📍
🌸 完结
最后,相关算法的代码也上传到gitee或者github上了。
乘风破浪会有时 直挂云帆济沧海
希望从明天开始,一起加油努力吧,成就更好的自己。
🥂 虽然这篇文章完结了,但是我还在,永不完结。我会努力保持写文章。来日方长,何惧车遥马慢!✨✨✨
💟 感谢各位看到这里!愿你韶华不负,青春无悔!让我们一起加油吧! 🌼🌼🌼
💖 学到这里,今天的世界打烊了,晚安!🌙🌙🌙
相关文章:
重启人生计划-拒绝内耗
🥳🥳🥳 茫茫人海千千万万,感谢这一刻你看到了我的文章,感谢观赏,大家好呀,我是最爱吃鱼罐头,大家可以叫鱼罐头呦~🥳🥳🥳 如果你觉得这个【重启人生…...
盘点电脑开机慢的几大高频原因
常规的话一台电脑正常我们都要用个2年以上的时间,有的可能更长,5年的都有,而电脑目前占多数的主流操作系统就是微软的Windows。那么随着使用年限的增加,无论是系统还是电脑硬件,都会随着使用次数和使用的时间的增加而有损耗,系统软件上就是文件越来越臃肿,空间越来越小,…...
2-64 基于matlab的Consensus-Based Bundle Algorithm (CBBA)算法
基于matlab的Consensus-Based Bundle Algorithm (CBBA)算法,可为异构代理网络上的多代理多任务分配问题提供良好的解决方案。支持具有有效时间窗口的任务、异构代理-任务兼容性要求,以及平衡任务奖励和燃料成本的得分函数。奖励和燃料成本的分数函数。程…...
Win10 去掉桌面右上角 了解有关此图片的信息
1. 进入注册表 Win R运行regedit 2. 找到以下路径 计算机\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel 3. 新建 DWORD(32位)值(D) 右击 NewStartPanel新建 DWORD…...
tcpdump入门——抓取三次握手数据包
1. 使用docker启动一个tcp应用 参考:https://blog.csdn.net/LONG_Yi_1994/article/details/141175526 2. 获取容器id docker ps |grep gochat 3. 获取容器的 PID 首先,你需要获得容器的进程 ID(PID)。可以使用 docker inspect…...
漏洞复现-GitLab任意读取文件(CVE-2023-2825)
1.漏洞描述 GitLab是一个用于仓库管理系统的开源项目,其使用Git作为代码管理工具,可通过Web界面访问公开或私人项目。据悉,该漏洞影响 GitLab社区版(CE)和企业版(EE)的 16.0.0 版本,其它更早的版本几乎都不受影响。 该漏洞存在于GitLab CE/EE版本16.0.0…...
二叉树——9.找树左下角的值
力扣题目链接 给定一个二叉树,在树的最后一行找到最左边的值。 示例: 输出:7 题干很简单,找到树的最后一行,在该行找到最左边的值,结合完整代码进行分析。 完整代码如下: class Solution:d…...
如何用github制作个人网站
这里整理了一些参考资料。总结来说,如果系统学过html网页制作的话,可以不用看这篇博客了;这里适合于小白,就是那种 没有做过网页、打算以别人优秀的个人主页为框架做网页的小白。 一、简单说明 这是利用github.io来制作网页的&a…...
二.PhotoKit - 相册权限(彻底读懂权限管理)
引言 用户的照片和视频算是用户最私密的数据之一,由于内置的隐私保护功能,APP只有在用户明确授权的前提下才能访问用户的照片库。从iOS14 开始,PhotoKit进一步增强了用户的隐私控制,用户可以选择指定的照片或者视频资源的访问权限…...
二叉树------最小堆,最大堆。
什么是最小堆: 堆是一种二叉树,最小堆中所有父亲节点的值都要比自己的子节点的值要小。而根节点称为堆顶。根据定义我们可以得到堆中最小元素就在堆顶。(节点左上角是编号,内部是元素值) 假设该图中的堆顶元素是24呢&a…...
预约功能的知识整理
前置知识 如果项目为小程序的开发项目中: 我们确定数据库中有的字段有: 预约人姓名、手机号、家人名称、预约时间 根据我们的经定一表必须要有的6个字段: 主键、创建时间、修改时间、创建人、修改人、备注 使用我们现在有的字段为: 主键…...
Linux的常用操作-02
一:Linux的系统目录结构 /bin bin是ary的缩写,这个目录存放着最经常用的命令 /boot:这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件。 /dev:dev是Device(设备)的缩写,该目录下存放的是Lin…...
Android Studio 连接手机进行调试
总所周知,Android Studio里的虚拟手机下载后又大又难用。不如直接连手机用。本篇文章主要内容为Android Studio怎么连接手机进行程序调试。 1. 在AndroidSDK中下载google USB Driver: 2. 连接手机: 进入电脑设备管理器界面。并点开便携设备,…...
Vue3项目创建及相关配置
Vue是一种用于构建用户界面的JavaScript框架。它采用了一种称为MVVM(Model-View-ViewModel)的架构模式。 MVVM是一种将用户界面与业务逻辑和数据分离的设计模式。它包括三个部分: Model(模型):表示应用程序…...
【Python】Python中一些有趣的用法
Python是一种非常灵活和强大的编程语言,它有很多有趣的用法,以下是一些例子: 一行代码实现FizzBuzz: print(\n.join([FizzBuzz[i%3*4:i%5*8:-1] or str(i) for i in range(1, 101)]))使用列表推导式生成斐波那契数列: …...
RCE复现问题和研究
目录 先了解一些常见的知识点 PHP常见命令执行函数 call_user_func eval() call_user_func_array array_filter 实战演练(RCE)PHP Eval函数参数限制在16个字符的情况下 ,如何拿到Webshell? 1、长度…...
MySQL中的索引——适合创建索引的情况
1.适合创建索引的情况 1、字段的数值有唯一性的限制 2、频繁作为 WHERE 查询条件的字段 某个字段在 SELECT 语句的 WHERE 条件中经常被使用到,那么就需要给这个字段创建索引了。尤其是在数据量大的情况下,创建普通索引就可以大幅提升数据查询的效率。 …...
5款在线伪原创改写软件,智能改写文章效果好
在这个信息爆炸的时代,内容创作变得愈发重要,而对于创作者来说,有时需要一些得力的伪原创改写工具来辅助我们更好地改写出高质量的内容。今天我要和大家分享5款令人惊喜的在线伪原创改写软件,它们以出色的智能改写效果,…...
opencv-python图像增强四:多曝光融合(方法一)
文章目录 一、简介:二、多曝光融合方案:三、算法实现步骤3.1 读取图像与曝光时间:3.2 计算响应曲线并合并3.3 色调映射 四:整体代码实现五:效果 一、简介: 在摄影和计算机视觉领域,高动态范围&…...
Qt 实战(9)窗体 | 9.2、QDialog
文章目录 一、QDialog1、基本概念2、常用特性2.1、模态与非模态2.2、数据交互 3、总结 前言: Qt框架中的QDialog类是一个功能强大且灵活的对话框控件,广泛应用于各种GUI(图形用户界面)应用程序中,用于处理用户输入、消…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...


