开开心心带你学习MySQL数据库之第八篇

索引和事务
~~ 数据库运行的原理知识 + 面试题
索引
索引(index) => 目录
索引存在的意义,就是为了加快查找速度!!(省略了遍历的过程)
查找速度是快了,但是付出了一定的代价!!
1.需要付出额外的空间代价来保存索引数据
2.索引可能会拖慢新增,删除,修改的速度
~~ 以写小论文为例
论文最前面要生成目录(word,能自动生成目录)
如果word没有这个功能,手动维护,一定会非常麻烦的
整体来说,还是认为索引是利大于弊的~~
实际开发中,查询场景一般要比增删改频率高很多!!!
索引的使用
~~ 查看索引
show index from 表名;
~~ 创建索引
create index 索引名 on 表名(列名);
创建主键约束(PRIMARY KEY),唯一约束(UNIQUE),外键约束(FOREIGN KEY)时,会自动创建对应列的索引
创建索引操作,可能很危险!!!
如果表里的数据很大, 这个建立索引的开销也会很大!!!
比如有一本很厚的书,现在让你给这个书手动的弄一份目录出来~~ 工作量巨大
~~ 好的做法,是创建表之初就把索引设定好
~~ 如果表里已经有很多数据,索引就别动了
~~ 删除索引
drop index 索引名 on 表名;
和创建索引类似,删除索引也可能存在风险!!!
探索索引背后的数据结构
可以用来加快查询的数据结构?
~~ 二叉搜索树
~~ 哈希表
实际上, MySQL并非使用以上的两个数据结构
原因:
二叉搜索树 => 如果元素个数多了,树的高度就会比较高~~ 树的高度相当于比较次数,对于数据库来说,则是IO访问次数,数据库里的数据在硬盘上.
哈希表 => 哈希表虽然查询的快,但是不能支持范围查询,也不能支持模糊匹配
B+ 树 => 索引的关键结构 ~~为了数据库索引,量身定做的数据结构
B+ 树
先了解B树,再来了解B+ 树
B树
B树,也叫做B-树~~ 此处–是“连接符",不是减号!!!千万不要念成B减树
B树可以认为是一个N叉搜索树,与二叉搜索树(二叉搜索树的度为2)进行类比了解
树的度 => 所有节点的度的最大值~~ 节点的度是有几个孩子(孩子节点个数)

当节点的子树多了,节点上保存的key多了意味着在同样key 的个数的前提下B 树的高度就要比二叉搜索树低很多!!
树的高度越高,进行查询比较的时候访问磁盘的次数就越多!!!效率就越低了
B+ 树
B+ 树,在B树的基础上又做出改进 ~~(也是N叉搜索树)

B+树的特点
1.一个节点,可以存储N个key,N个key划分出了N个区间~~(而不是N+1个区间).
2.每个节点中的 key 的值,都会在子节点中也存在(同时该key是子节点的最大值).
3.B+树的叶子节点,是首尾相连,类似于一个链表.
~~ 由于B+树特点1,2,3导致整个树的所有数据都是包含在叶子节点中的,(所有非叶子节点中的key最终都会出现在叶子节点中).
4.由于叶子节点,是完整的数据集合,只在叶子节点这里存储数据表的每一行的数据.而非叶子节点,只存key值本身即可.
B+树的优势
1.当前一个节点保存更多的key,最终树的高度是相对更矮的.查询的时候减少了IO(这里IO特指硬盘的访问)访问次数.(和B树是一样的).
2.所有的查询最终都会落到叶子节点上.(查询任何一个数据,经过的IO访问次数,是一样的) => 稳定 ~~ 这个稳定,是很关键的,稳定能够让程序猿对于程序的执行效率有一个更准确的评估
3.B+树的所有的叶子节点,构成链表,此时比较方便进行范围查询
4.由于数据都在叶子节点上,非叶子节点,只存储key,导致非叶子节点,占用空间是比较小的~~这些非叶子节点就可能在内存中缓存(或者是缓存一部分).又进一步减少了IO的次数!
如果这个表里有多个索引呢?针对id有主键索引,针对name又有一个索引表的数据
~~ 还是按照id 为主键,构建出B+树通过叶子节点组织所有的数据行
~~ 其次,针对 name 这一列,会构建另外一个B+树但是这个B+树的叶子节点就不再存储这一行的完整数据,而是存主键id 是啥
~~ 此时,如果你根据 name 来查询,查到叶子节点得到的只是主键 id,还需要再通过主键 id 去主键的B+树里再查一次~~ (查两次B+树)
(上述过程称为"回表",这个过程,都是MySQL 自动完成的,用户感知不到)
面试八股文
~~对于实际工作,用处不大(工作中不会让你实现一个B+树的),但是面试老考(只能尽量掌握)
事务
经典场景: 转账
account(id, balance)
id balance
1 1000
2 0
1给2转账500
步骤:
1)update account set balance = balance - 500 where id = 1;
2)update account set balance = balance + 500 where id = 2;
假设,在执行转账过程中,执行完1之后,数据库崩溃了/主机宕机此时这个转账就僵硬了!
~~ 1的钱扣了,但是2的钱没到账!
事务就是为了解决上述的问题
~~ 事务的本质就是把多个sqI 语句给打包成一个整体
~~ 要么全都执行成功,要么就一个都不执行,而不会出现"执行一半"这样的中间状态!!!
淘宝买东西~~ 下单
~~ 下订单的同时,要进行支付
~~ 你这边账户扣钱了,同时订单表中也会生成一个对应的数据
“把多个sqI 语句给打包成一个整体” => 事务的原子性(atom) => 计算机中不可分割的基本单位
“一个都不执行” => 不是真的没执行,而是"看起来好像没执行一样" => 具体是执行了,执行一半出错了,出错之后,选择了恢复现场,把数据还原成未执行之前的状态了,类似于ctrl+z ~~ 这个恢复数据的操作,称为“回滚" (rollback)
进行回滚的时候,是怎么知道回滚是恢复到啥样的状态呢??
此处是需要额外的部分来记录事务中的操作步骤(数据库里专门有个用来记录事务的日志)
正因为如此,使用事务的时候,执行sql的开销是更大的,效率是更低的!!!
~~ 只要是执行失败,都会触发回滚
使用
(1)开启事务:start transaction;
(2)执行多条SQL语句;
(3)回滚或提交:rollback/commit;
注:rollback即是全部失败,commit即是全部成功
-- 开启事务
start transaction;-- 中间就是要执行的每一步操作
update account set balance = balance - 500 where id = 1;
update account set balance = balance + 500 where id = 2;-- 提交事务,到这一步,相当于事务就执行完了
commit;
事务使用起来容易,理解起来困难
⭐️⭐️⭐️数据库的事务,有四个关键的特性(面试八股文,~~ 经典面试题):
1.原子性~~ (事务最核心的特性)~~ 事务的初心
2.一致性~~ 事务执行前后,数据得是靠谱的 ~~
3.持久性~~ 事务修改的内容是写到硬盘上的,持久存在的,重启也不丢失
4.隔离性⭐️⭐️⭐️⭐️⭐️
~~ 这个隔离性是为了解决"并发"执行事务,引起的问题
例子:一个餐馆(服务器),同一时刻要给多个顾客(客户端)提供服务
这些顾客提出的请求,是"一个接一个"的来的嘛?还是一股脑一起来了一波?? => 都有可能
“一股脑一起来了一波“ => 此时,服务器同时处理多个客户端的请求,就称为“并发"(齐头并进的感觉)
~~ 数据库也是服务器,就有可能多个客户端都给服务器提交事务
~~ 数据库就需要并发的处理多个事务
~~ 如果并发的这些事务,是修改不同的表/不同的数据,没啥事~~
~~ 如果修改的是同一个表/同一个数据 => 可能会带来一定的问题的!!!~~
~~ 比如多个客户端一起尝试对同一个账户进行转账操作,此时就可能会把这个数据给搞乱了
事务的隔离性,存在的意义就是为了在数据库并发处理事务的时候不会有问题(即使有问题,问题也不大)
那么并发处理事务,可能会有哪些问题.以及这些问题数据库的隔离性是怎样解决的~~ (挺麻烦的)
并发执行事务可能产生的问题
—.脏读问题
场景: 我在图书馆写代码(上课要交的作业),在我写的过程中,有一个同班同学,在我身后经过,他喵了一眼我的屏幕~~ 看到了我的代码中写了一些内容,然后他就走了~~ 他走了之后,可能会出现~~ 我发现我的代码写的有问题,不符合题意,又改了~~ 又或者我写的代码没有问题,又没改.
一个事务A正在对数据进行修改的过程中,还没提交之前,另外一个事务B,也对同一个数据进行了读取.此时B的读操作就称为“脏读",读到的数据也称为“脏数据”~~ 脏的意思,是"无效",不是埋汰的意思.
~~ 为啥说无效?很可能,A回头又把数据给改了.
为了解决脏读问题, mysql 引入"写操作加锁"这样的机制
大概场景就是: 我和同学商量好~~ 我写代码的过程中,你别来看~~ 等我改完,提交到码云上,你再通过我的码云来看 => 写的时候不能看(给写操作加锁),写完了才能看.
当我写的时候,同学没法读,意味着我的"写操作"和同学的"读操作"不能并发了~~(不能同时执行了).
这个给写加锁操作,就降低了并发程度(降低了效率),提高了隔离性(提高了数据的准确性).
二.不可重复读
还是我写代码,同学想看一看怎么做
~~ 约定好,我写的时候,不许看,等我提交了,再通过码云来看(约定好写加锁了)
~~ 我写代码,提交了版本1.此时就有同学开始读这个代码了
~~ 突然发现题目还存在更优解,于是我又打开代码,继续修改代码,然后又提交版本2
~~ 这个同学开始读的过程中,读到的是版本1的代码,读着读着,我提交了版本2,此时这个同学读的代码,刷的一下变样了!!这个问题,叫做"不可重复读" => 第一次和第二次读到的结果不一样.
事务1已经提交了数据.此时事务2开始去读取数据.在读取过程中,事务3又提交了新的数据.
此时意味着同一个事务2之内,多次读数据,读出来的结果是不相同的~~ (预期是一个事务中,多次读取结果得一样)就叫做"不可重复读”~~ 第二次读取的结果不能复现第一次的结果 => 好比看微信余额,第一次看一眼,发现余额是这些,过几秒啥也没做再看一眼,第二次看一眼的时候,余额就变了,钱没了,这就出大问题了,必须确保两次查看时余额不变,才符合现实生活.
~~ 同学发现了这个问题之后,知道了是在他读的过程中,我又改代码了,于是来找我,和我约定
~~ 他/她读代码的时候,我也不能修改!!!
~~ 刚才约定的是,我修改的时侯,提交之前,同学不要读,是给写加锁
~~ 现在是约定,同学读的时候,我不能修改,就是给读加锁
~~ 在同学读完了之后,我就可以修改了,即加锁之后就会进行解锁
通过这个读加锁,又进一步的降低了事务的并发处理能力(处理效率也降低了),提高了事务的隔离性(数据的准确性又提高了)
三.幻读
当前已经约定了读加锁和写加锁,解决了不可重复读和脏读问题
由于约定了读加锁,同学读的时候,我不能改代码了
~~ 我在这干的等着??光摸鱼打王者,有点难受(主要是玩这游戏,输多赢少,本就不太爱玩了,恰好又输了一把)
~~ 所以我想了办法,同学读Student.java,那好,我就创建一个Teacher.java,就写这个代码呗!!
~~ 这样的情况,大多数情况下都没事,少数情况下,个别同学发现了,读代码读着突然多出个Teacher.java这个文件,有的同学就觉得接收不了
在读加锁和写加锁的前提下,一个事务两次读取同一个数据,发现读取的数据值是一样的,但是结果集不一样
~~ (Studentjava 代码内容不变,但是第一次看到的是只有 Student.java 这个文件,第二次看到的是 Student.java 和Teacher.java 这两个文件了…),这种就称为"幻读’.
数据库使用"串行化"这样的方式来解决幻读.彻底放弃并发处理事务,一个接一个的串行的处理事务.这样做,并发程度是最低的(效率最慢的),隔离性是最高的(准确性也是最高的)
~~ 相当于是同学们要求,在他们读代码的时候,我不要摸电脑,必须强制摸鱼打王者!!
上述三个问题脏读,不可重复读,幻读就是并发处理事务的三个典型问题
对应上述问题, mysql提供了4种隔离级别,就对应上面的几个情况
以下是四种隔离级别
| read uncommitted | 没有进行任何锁限制,并发最高(效率最高),隔离性最低(准确性低) |
|---|---|
| read committed | 给写加锁了,并发程度降低,隔离性提高了 |
| repeatable read | 给写和读都加锁,并发程度又降低,隔离性又提高了 |
| serializable | 串行化,并发程度最低,隔离性最高 |
| 脏读 | 给写加锁 | read committed | 并发程度降低,隔离性提高了 |
|---|---|---|---|
| 不可重复读 | 给读加锁 | repeatable read | 并发程度又降低,隔离性又提高了 |
| 幻读 | 彻底串行化 | serializable | 并发程度最低,隔离性最高 |
四种隔离级别是mysqI 内置的机制,
~~ 可以通过修改mysqI的配置文件, 来设置当前 mysql 工作在哪种状态下
这几个隔离级别,如何选择???
~~ 这几个级别没有好坏,在准确性和效率之间进行权衡
~~ 看实际需求,看业务场景
~~ 转账的时候,一分钱都不能差,哪怕慢点,也得转对!!!此时准确性要拉满,效率不关键
~~ 抖音,点赞,一个视频有多少赞,要求快,赞的数量差个十个八个,都没事,此时追求的是效率,准确性就不关键
级别是mysqI 内置的机制,
~~ 可以通过修改mysqI的配置文件, 来设置当前 mysql 工作在哪种状态下
相关文章:
开开心心带你学习MySQL数据库之第八篇
索引和事务 ~~ 数据库运行的原理知识 面试题 索引 索引(index) > 目录 索引存在的意义,就是为了加快查找速度!!(省略了遍历的过程) 查找速度是快了,但是付出了一定的代价!! 1.需要付出额外的空间代价来保存索引数据 2.索引可能会拖慢新增,删除,修改的速度 ~~ …...
yml配置动态数据源(数据库@DS)与引起(If you want an embedded database (H2, HSQL or Derby))类问题
1:yml 配置 spring:datasource:dynamic:datasource:master:url: jdbc:mysql://192.168.11.50:3306/dsdd?characterEncodingUTF-8&useUnicodetrue&useSSLfalse&tinyInt1isBitfalse&allowPublicKeyRetrievaltrue&serverTimezoneUTCusername: ro…...
yolov5运行过程遇到的小问题(随时更新)
1.关于git的问题 解决办法:插入下面代码 import os os.environ["GIT_PYTHON_REFRESH"] "quiet"2.页面太小无法完成操作 解决办法: 如果不好使再考虑降低Batch_Size大小或者调整虚拟内存可用硬盘空间大小!(调整虚拟内存…...
使用FabricJS创建Image对象的JSON表示
本篇文章介绍一下如何创建图像的 JSON 表示形式 使用 FabricJS 的对象。我们可以通过创建一个实例来创建一个 Image 对象 织物.图像。由于它是FabricJS的基本元素之一,我们也可以轻松地 通过应用角度、不透明度等属性来自定义它。为了创建 JSON Image 对象的表示&am…...
【牛客刷题】反转固定区间链表、每k个节点一组反转
链表内指定区间反转_牛客题霸_牛客网 ListNode* reverseList(ListNode* head, ListNode* tail) {ListNode* pre nullptr;ListNode* cur head;while (cur ! tail) { 最后cur就是tailListNode* temp cur->next;cur->next pre;pre cur;cur temp;}return pre;}ListNode…...
算法:数组常见套路1---双指针、取模、打擂台法
文章来源: https://blog.csdn.net/weixin_45630258/article/details/132738318 欢迎各位大佬指点、三连 一、数组的合并–双指针[快慢指针] 1、题目: 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ࿰…...
App 出海实践:Google Play 结算系统
作者:业志陈 现如今,App 出海热度不减,是很多公司和个人开发者选择的一个市场方向。App 为了实现盈利,除了接入广告这种最常见的变现方式外,就是通过提供各类虚拟商品或者是会员服务来吸引用户付费了,此时 …...
国际慈善日 | 追寻大爱无疆,拓世科技集团的公益之路
每年的9月5日,是联合国大会正式选定的国际慈善日。这一天的设立,旨在通过提高公众对慈善活动的意识,鼓励慈善公益活动通过各种形式在全球范围内得到增强和发展。这是一个向慈善公益事业致敬的日子,同时也是呼吁全球团结一致共同发…...
关于DNS的一些认识
目录 什么是DNS? 一台具有单个DNS的机器可以拥有多个地址吗? 一台计算机可以有多个属于不同顶级域的DNS名字吗? 什么是DNS? DNS是域名系统(Domain Name System)的缩写,它是互联网中用于将域名…...
游戏性能优化
Unity性能优化主要包括以下方面: 1.渲染性能 。包括减少Draw Calls、减少三角面数、使用LOD、使用批处理技术、减少实时光源等,以提高游戏的帧率和渲染效率。 2.内存性能 。包括使用对象池、使用合适的纹理、使用异步加载资源等,以减少内存占…...
公开游戏、基于有向图的游戏
目录 〇,背景 一,公开游戏、策梅洛定理 1,公开游戏 2,策梅洛定理 二,有向图游戏 1,狭义有向图游戏 2,广义有向图游戏 3,狭义有向图游戏的SG数 4,Bash Game 力扣…...
CSS学习笔记05
CSS笔记05 定位 position CSS 属性position - 用于指定一个元素在文档中的定位方式。top,right,bottom 和 left 属性则决定了该元素的最终位置。position 有以下常用的属性值: position: static; - 默认值。指定元素使用正常的布局行为&am…...
Linux查看指定端口是否被占用
在Linux中,可以使用多种方法来检查一个特定端口(例如3306,通常由MySQL使用)是否被占用: 使用netstat命令: 如果系统中已安装了netstat,可以使用以下命令检查3306端口: netstat -tuln | grep 330…...
【Python 自动化】小说推文一键生成思路概述
最近看了一下小说推文成品软件的思路,发现可以完全迁移到我的 BookerAutoVideo 上面来。这篇短文里面,我试着分析一下整个推文视频生成的流程,以及简要阐述一下有什么工具。 整体流程是这样: 分句 原文是按照段落组织的…...
MySQL中的字符集与排序规则详解
在 MySQL 中,字符集(Character Set)用于确定可以在数据库中存储的字符集合,而排序规则(Collation)用于指定比较和排序字符串的规则。下面是关于 MySQL 中字符集和排序规则的一些详细信息: 字符集…...
Java中如何进行加锁??
笔者在上篇文章介绍了线程安全的问题,接下来本篇文章就是来讲解如何避免线程安全问题~~ 前言:创建两个线程,每个线程都实现对同一个变量count各自自增5W次,我们来看一下代码: class Counter{private int count0;publi…...
Pytorch3D多角度渲染.obj模型
3D理解在从自动驾驶汽车和自主机器人到虚拟现实和增强现实的众多应用中发挥着至关重要的作用。在过去的一年里,PyTorch3D已经成为一个越来越流行的开源框架,用于使用Python进行3D深度学习。值得庆幸的是,PyTorch3D 库背后的人员已经完成了实现…...
MyBatisPlus 基础Mapperr接口:增删改查
MyBatisPlus 基础Mapper接口:增删改查 插入一条数据 代码 Testpublic void insert() {User user new User();user.setId(6L);user.setName("张三");user.setAge(25);user.setEmail("zhangsanexample.com");userMapper.insert(user);}日志 数…...
计算机网络与技术——概述
😊计算机网络与技术——概述 👻前言🥏信息时代下计算机网络的发展🌏互联网概述📡计算机网络基本概念📡互联网发展三阶段📡互联网的标准化 🌏互联网的组成📡互联网的边缘部…...
详解TCP/IP协议第三篇:通信数据在OSI通信模型的上下传输
文章目录 一:OSI通信模型间数据传输展示 二:应用层到会话层解析 1:应用层 2:表现层 3:会话层...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
在 Kubernetes 集群中,如何在保障应用高可用的同时有效地管理资源,一直是运维人员和开发者关注的重点。随着微服务架构的普及,集群内各个服务的负载波动日趋明显,传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
