决战圣地玛丽乔亚Day21----Mysql事务相关及结构相关
算法:
组合问题的剪纸优化.
上次的组合问题,我们是对层数的每个元素遍历一遍,在某些情况下是没有必要的,例如,4个数取4个组合。那么我们的起始位置必须要满足个数的条件,那么从2开始取,最多取2,3,4三个数,不满足条件可以舍去。
接下来看一下优化过程如下:
-
已经选择的元素个数:path.size();
-
所需需要的元素个数为: k - path.size();
-
列表中剩余元素(n-i) >= 所需需要的元素个数(k - path.size())
-
在集合n中至多要从该起始位置 : i <= n - (k - path.size()) + 1,开始遍历
为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。
举个例子,n = 4,k = 3, 目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2。
从2开始搜索都是合理的,可以是组合[2, 3, 4]。
这里大家想不懂的话,建议也举一个例子,就知道是不是要+1了。
所以优化之后的for循环是:
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置
优化后的代码:
class Solution { private: vector<vector<int>> result; vector<int> path; void backtracking(int n, int k, int startIndex) { if (path.size() == k) { result.push_back(path); return; } for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) { // 优化的地方 path.push_back(i); // 处理节点 backtracking(n, k, i + 1); path.pop_back(); // 回溯,撤销处理的节点 } } public: vector<vector<int>> combine(int n, int k) { backtracking(n, k, 1); return result; } };
LeetCode216.组合的总和:
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
- 所有数字都是正整数。
- 解集不能包含重复的组合。
示例 1: 输入: k = 3, n = 7 输出: [[1,2,4]]
示例 2: 输入: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]]
本题和上面的组合如出一辙。
手写的代码如下:
package com.dwj; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class Main { LinkedList<Integer> path = new LinkedList<>(); List<List<Integer>> resultList = new ArrayList<>(); int sum = 0; public static void main(String[] args) { Main main = new Main(); List<List<Integer>> result = main.combine(7,3); System.out.println(result); } public List<List<Integer>> combine(int n, int k) { backtracking(n,k,1); return resultList; } private void backtracking(int n, int k, int startIndex){ //2.终止条件 if(path.size()==k && sum == n){ resultList.add(new ArrayList<>(path)); return; } if(sum>n){ return ; } //3.单层遍历逻辑
// 也可以改为 if (path.size() > k) return; 执行效率上是一样的
for(int i=startIndex; i<=9-(k-path.size())+1;i++){ path.add(i); sum += i; backtracking(n,k,i+1); path.removeLast(); sum -= i; } } }
需要注意的点是,满足条件返回resultList的时候,需要注意
resultList.add(new ArrayList<>(path)) 不能直接 resultList.add(path) 由于这种写法,导致最终执行无效。
剪纸操作:
for(int i=startIndex; i<=9-(k-path.size())+1;i++)
k-path.size代表当前还需要多少个元素满足个数。 如果当前k=3 path= 1 k-path.size代表还需要两个元素才能满足个数的需求。
然后通过总数9-2 = 7 代表从7开始, [7,8,9]是最后的一个满足条件. +1是由于使用<=也就是是一个左闭右开
想不明白大不了不去剪纸,用最笨的方法,i<=9
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
为什么聚簇索引建议使用自增主键?
我觉得这段话说的很好:
上文讨论过InnoDB的索引实现,InnoDB使用聚集索引,数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点)。
如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页。
这样就会形成一个紧凑的索引结构,近似顺序填满。由于每次插入时也不需要移动已有数据,因此效率很高,也不会增加很多开销在维护索引上。
如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置。
此时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。
因此,只要可以,请尽量在InnoDB上采用自增字段做主键。
Mysql的事务隔离级别有哪些?默认的隔离级别是什么?
mysql的事务隔离级别有:
1)UncommitedRead未提交读,可以读取到未提交的事务。 A事务可以读到B事务未提交的数据,B事务返回不想提交了,但是数据已经被A读到了,A读到的是脏数据。脏读现象出现。
2)Read-commited不可重复读,重复读结果不一样。 一个事务提交后,数据才能被其他事务看到。并且其他事务每次对数据进行修改和提交,都能读到最新数据。 A事务做两次查询,查询的途中B事务进行数据的修改,B事务在两次查询之间提交事务,因为只能读到提交的数据,所以A出现了两次查询不一致的结果。
3)RepeatedRead 可重复读(Mysql默认):在不可重复读的基础上,让两次读到的数据是一致的。但是可能存在幻读的问题,这个在下面进行介绍。
MVCC机制多版本并发控制:保证InnoDB下执行一致性读操作。
InnoDB会给每行增加两个隐藏字段实现MVCC,创建时间和过期时间,但是实际存的是版本号,每次开启事务版本号会增加。
Select操作是快照读读历史版本,其他操作是当前读。
select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)
4)Serializable:串行化,读写数据锁表。效率极低。
持久性和一致性的区别?和CAP一致性的区别?分布式事务是如何实现隔离级别的?
什么是幻读?是如何解决幻读的?
总体来说,幻读的产生是由于我们对某一区间进行读操作的过程中,被另一事物进行了改动导致两次读取内容不同。 注意这里讲的是范围。
在mysql中,对当前读和快照读进行了不同的处理解决了幻读的问题。(当前读:更新操作 快照读:普通select,不包括select for update这种上锁)
对于当前读:我们使用间隙锁,在读取某一行数据时,选取左右临界点,锁住当前区域的数据,如果有其他锁请求会被阻塞。
对于快照读:使用了mvcc多版本并发控制机制,通过记录版本号的方式保存数据。 如果是普通的select操作,我们读取最近一次的快照交给事务,如果是更新操作,需要更新版本号。
默认的事务隔离级别是RR。
更细致的部分参考:https://www.cnblogs.com/dwj-ngu/p/17141962.html
SQL优化部分:
1.explain
explain [sql]
参数含义:
select_type:查询的类型
partitions:匹配的分区,分区表命中的分区情况,非分区表该字段为空。
type:
NULL > system > const > eq_ref > ref > ref_or_null > index_merge > range > index > ALL
NULL: 执行阶段无须访问表和索引,最快。不需要查表的数学计算等...
system:表只有一行数据,const类型的特例,可忽略
eq_ref: 连表查询,按链表的主键或唯一外键联合查询。连接起来是一对一
ref: 单表或多表链接查询,外键一对多
ref_or_null: ref的基础上可以搜索null值
index_merge:多索引联合查询最后去交并集
range:范围查询,=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()或者like等运算符的查询中。
index:遍历索引树,由于索引文件比数据文件小,所以比all快一点。
all:遍历所有数据。
possible_keys:这个表里面存在且可能会被使用的索引,可能会在这个字段下面出现,但是一般都以key
为准
key:使用的索引,如果是覆盖索引,那么只会出现在key里面。
ken_len:索引长度(这个值越短越有利)
ref: 索引的哪一列被使用了
rows:返回结果行数
filtered:是查询的行数与总行数的比值
extra:这一字段包含不适合在其他列显示,但是也非常重要的额外信息
这一字段包含不适合在其他列显示,但是也非常重要的额外信息。
-
Using filesort
表示当SQL中有一个地方需要对一些数据进行排序的时候,优化器找不到能够使用的索引,所以只能使用外部的索引排序,外部排序就不断的在磁盘和内存中交换数据,这样就摆脱不了很多次磁盘IO,以至于SQL执行的效率很低。反之呢?由于索引的底层是B+Tree实现的,他的叶子节点本来就是有序的,这样的查询能不爽吗?EXPLAIN SELECT * FROM course AS C ORDER BY C.`name`
type possible_keys key key_len ref rows filtered Extra ------ ------------- ------ ------- ------ ------ -------- ---------------- ALL (NULL) (NULL) (NULL) (NULL) 20 100.00 Using filesort
没有给
C.name
建立索引,所以在根据C.name
排序的时候,他就使用了外部排序 -
Using tempporary
表示在对MySQL查询结果进行排序时,使用了临时表,,这样的查询效率是比外部排序更低的,常见于order by
和group by
。EXPLAIN SELECT C.`name` FROM course AS C GROUP BY C.`name`
possible_keys key key_len ref rows filtered Extra ------------- ------ ------- ------ ------ -------- --------------------------------- (NULL) (NULL) (NULL) (NULL) 20 100.00 Using temporary; Using filesort
上面这个查询就是同时触发了
Using temporary
和Using filesort
,可谓是雪上加霜。 Using index
表示使用了索引,很优秀👍。Using where
使用了where
但是好像没啥用。Using join buffer
表明使用了连接缓存,比如说在查询的时候,多表join
的次数非常多,那么将配置文件中的缓冲区的join buffer
调大一些。impossible where
筛选条件没能筛选出任何东西distinct
优化distinct
操作,在找到第一匹配的元组后即停止找同样值的动作
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
2017-02-27 枚举类.