【MySQL系列】第四节.MySQL索引事务

 作者简介:大家好,我是未央;

博客首页:未央.303

系列专栏:Mysql系列

每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!

文章目录

前言

一、索引

1.1 索引概念

1.2 为什么要使用索引

1.3 索引的使用场景

1.4 索引的使用

1.4.1 查看索引

1.4.2 创建索引

1.4.3 删除索引

二、事务

         2.1 为什么使用事务

2.2 事务的概念

2.3 事务的特性

2.3.1 原子性

2.3.2 一致性

2.3.3 持久性

2.3.4 隔离性

2.4 事务的使用

后续

总结



前言

本节课我们将学习关于MySQL的索引和事务的章节,本节内容十分重要,能够让我们的MySQL操作得到很大的简化,所以务必学好本节内容,了解好索引和事务的相关特性与作用,并且能够正确和灵活的使用他们.


一、索引

1.1 索引概念

定义:

如果说 "索引" 这个词语 对你们有一点抽象,那么 可以换一个词语来表达 —— "目录"

每一本书,都有自己的目录

想观看某一章节内容,翻开目录,它就会告诉你 该章节在多少页

这就比一页一页的翻 要高效率的多

目录 所存在的意义,就是在加快查找的速度

想要理解 索引,可以先来理解 目录

图像解释:


1.2 为什么要使用索引

说白了,索引 实质上是一张描述索引列的列值与原表中记录行之间一一对应关系的有序表。

在 MySQL 中,通常有以下两种方式访问数据库表的行数据:

1) 顺序访问

定义顺序访问是在表中实行全表扫描,从头到尾逐行遍历,直到在无序的行数据中找到符合条件的目标数据

                                                                                                                                                  

缺点顺序访问实现比较简单,但是当表中有大量数据的时候,需要从头到尾进行遍历,效率非常低下

2) 索引访问

索引访问是通过 遍历索引 来直接访问表中记录行的方式

使用方法:

使用这种方式的前提是 对表建立一个索引,在列上创建了索引之后,查找数据时可以直接根据该列上的索引找到对应记录行的位置,从而快捷地查找到数据。

                                                                                                                                                  

例子:

比如,在 student表 中,如果基于 student_id 建立了索引,系统就建立了一张 索引列到实际记录的映射表

当用户需要查找 student_id 的相关数据时,系统先在 student_id 索引上找到该记录,然后通过映射表直接找到数据行,并且返回该行数据

可以这样理解,一个表里面有很多列,一列数据所占用的空间比较大,只能放在磁盘上

做索引 常见的情况就是 拿其中的某一个 id 来做索引,单拎出来的 id 可是要比整个行都小多了

所以 扫描索引的速度一般远远大于扫描实际数据行的速度,即 采用索引的方式可以大大提高数据库的工作效率

优点:

简而言之,不使用索引,MySQL 就必须从第一条记录开始读完整个表,直到找出相关的行。表越大,查询数据所花费的时间就越多。如果表中查询的列有一个索引,MySQL 就能快速到达一个位置去搜索数据文件,而不必查看所有数据,这样将会节省很大一部分时间


1.3 索引的使用场景

"索引" 本质上是通过一些更复杂的数据结构,把所有待查询的记录给组织起来了,从而就能够加快查找的速度!!!

(1)消耗了额外的空间!!!

这一点 可以类似于新华字典,或者是写博客之类的:

新华字典的目录 需要耗费纸张吧,写博客如果加上目录 需要耗费一定的空间吧

(2)有了索引,可以加快 查询的速度,但是拖慢了 增删改的速度!!!

这一点 可以类比于目录,如果 张三同学 写了一本书,此时 书的内容已经写好了,并且目录已经写好了;但是,此时 张三同学 突然又想到了 某些好点子,或者又觉得书上的某些内容不好,或者是又想修改某一部分内容

那么,此时 张三同学 不仅仅是要修改书的内容了,书的目录也是要修改的,那肯定是拖慢了速度

索引使用场景:

即 索引也不是尽善尽美的,主要是看场景是否合适:

1.对于空间不紧张,对于时间更敏感,可以使用 索引(以空间换时间)
2.查询频繁,增删改不频繁,可以使用索引(其实,这个也是大多数的情况,比如说 教务系统)
所以说,满足了上述条件,就可以考虑 对表中的字段 创建索引,以提高查询效率

反之,如果非条件查询列,或经常做插入、修改操作,或磁盘空间不足时,不考虑创建索引


1.4 索引的使用

1.4.1 查看索引

代码:

show index from 表名;

虽然后面有许多,但是 现在主要关注的是 Key_name 和 Colum_name

                                                                                                                                                   

一开始,咋们是没有创建索引的

但是,虽然前面没有给这个 student表 手动创建索引,

却可以看到它自带了一个索引我们需要注意的是,一个表的主键列会自动带上索引,unique以及外键约束的列,也会自动带上索引

像 主键 这种,需要保证 记录不重复,

每次插入新纪录,都需要查询一下旧记录,看看新记录是否已经存在,判断是否重复,插入是否成功

此时,就需要进行频繁的查询当然,unique 和 外键约束 也是如此,需要进行频繁的查询


1.4.2 创建索引

代码:

create index 索引名 on 表名(列名);

我们可以创建索引

1.先看看 student表 的结构:

2.现在,我们可以创建一个索引:

3. 现在,我们就可以查看刚刚创建的索引:


1.4.3 删除索引

drop index 索引名 on 表名;

此时,我们可以删除 刚刚创建的 idx_student_name索引:

此时,索引删除成功

注意:

创建索引 和 删除索引,也是危险操作!!!

尤其是针对一个已经包含很大数据量的表 进行操作的时候!!

如果是针对一个大表,创建索引,就会导致大规模磁盘IO,直接把主机的磁盘IO吃满!!!

主机就卡了,无法对线上服务进行响应

二、事务

2.1 为什么使用事务

原因:在实际操作中,有些操作,希望是一个整体

举例:

假设,张三同学 谈了一个对象,那么 我们把中间某些流程简化一下,张三同学 肯定是希望把 给彩礼 => 领证 => 办酒席 这些环节 希望是一个整体

如果 中间的某些环节出现了问题,那么 希望能够把这些问题的影响降到最低

如果彩礼给完了,领证的时候,女方发现张三同学是一个渣男,后悔了 不想结婚了

女方想要反悔就得退回彩礼

如果彩礼给完了,证也领了,想反悔

那就需要先把彩礼退了,然后还得去民政局办个离婚证

这三个操作希望能够一气呵成,当做一个整体来进行!!!

如果执行中间过程中,出现异常,就需要把前面已经进行过的操作 进行回退/恢复

恢复成好像完全没有操作过的样子

此时,把这三个环节(一个整体),就可以视为一个 "事务"!!! 


2.2 事务的概念

事务就是把多个步骤,多个操作,打包成一个步骤,一个操作

其中任意一个步骤执行失败,都会进行回退,使这里的影响被降到最低


2.3 事务的特性

2.3.1 原子性

在数据库上涉及到很多和事务相关的操作!!!

最典型的:转账

举例:

李四 给 王五 转账转500,

涉及到的操作:

1.给 李四 -500    => SQL1
2.给 王五 +500   => SQL2
如果在执行SQL1之后,再执行SQL2的过程中,数据库出现问题了(宕机了),那么 李四就会减少500,而王五却并没有增加500,显然这个是非常不科学的

按正常的情况,要么两个都执行完,要么就一个都不执行!!!
这个就是事务最核心的特性:原子性!

(事务的原子性指的是,事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据改操作要全部执行,要么全部不执行;这种特性称为原子性 —— 是事务诞生的初衷

注意:此处的 "一个都不执行",不是真的没执行

           而是通过恢复的方式,把之前造成的影响给还原了

           这个还原的过程,称为 "回滚"(rollback)

数据库的事务回滚,是如何做到的?

数据库里的每个操作,在内部都有记录,尤其是事务内部的操作

如果事务中间出现问题,就可以根据之前的记录,来进行恢复了


2.3.2 一致性

事务的一致性指在一个事务执行之前和执行之后数据库都必须处于一致性状态

简单的来说,就是 一致数据是对的,没有纰漏

就比如上面的转账的例子,李四 给 王五 转账转500,李四 -500,那么王五就得要 +500;不能说 李四 -500 而王五 +400 


2.3.3 持久性

持久性,即 存储在磁盘上,事务进行的操作都会写在磁盘上,只要事务执行成功,造成的修改,就是永久化保存的了;哪怕重启主机,这样的改变也存在。

磁盘严格来说和硬盘不是一个东西,虽然都是外存,但是此处也就直接混用了。


2.3.4 隔离性

事务的隔离性:这个是 描述多个事务并发执行的时候,所产生的情况

举例:

正好 现在正处于疫情期间,相信大家对于 "隔离" 这个词语已经很熟悉了

其实,事务的隔离性 和 现在疫情的隔离意思差不多的

疫情的隔离,有几种级别:

1.定点医院隔离(隔离效果最好,出现交叉感染的概率最小,成本最高!!!)
2.指定酒店隔离(隔离效果比较好,成本比较高)
3.居家隔离/在学校隔离(隔离效果一般,成本比较低)
4.不隔离 (没啥隔离效果)
根据不同的隔离级别,严格情况不同,所以效果也是不同的

隔离的目的是:为了避免相互之间产生影响

数据库中的事务 彼此之间也是可能会相互影响的,

事务的隔离性也就是在描述事务执行过程中,影响能接受到啥程度

如果事务是一个一个执行的,那么还好;

但是如果事务是并发执行的,那么相互之间可能会造成影响

并发执行,可以简单粗暴的理解成,两个事物在同时执行!!!

在之前介绍过,一个数据库服务器 可以给多个客户端提供服务,

这个时候就可能会涉及到 说多个客户端同时尝试操作一个表,

就可能会产生这种并发事务的情况

比如说,现在这里有一张售票表(剩余票数1),

现在 客户端可能要执行 "买票事务":

1.先检查剩余的票数是否 > 0
2.如果 > 0 就修改收票表里的计数,让计数 -1
如果两个客户端不加限制,同时进行,那么就会带来麻烦:

客户端1 和 客户端2 都执行了 -1 操作,那么 实际上票数就变成了 -1

这种情况叫做 "超卖"!!

解析:

上述问题,就是两个事务之间产生了干扰和影响,

为了避免相互干扰,就引入了 "隔离性",通过隔离性来降低上述的影响

为啥要并发执行?

目标是为了提高执行效率!!! 

提高隔离性,带来的问题就是 数据更准确了,但是效率更低了

为了解决并发执行事务带来的问题,MySQL等数据库引入了 "隔离级别",可以让用户自行选择一个 适合自己当前业务场景的级别

先研究一下,并发执行事务的时候 还会有哪些问题?

(1)脏读问题(数据被污染了,不准了)

举个例子:

张三同学 在写代码,写了一个 Student类,写了一些属性和方法

在他写的过程中,李四走过来看了一会儿,就走了

在李四走了之后,张三同学 又把 Student类 里的实现又改了

此时,李四 读到的数据就是 "脏数据",上述的观察过程,就是 "脏读"

用数据库的术语来说,一个事务 A,在执行过程当中,对数据进行了一系列的修改。在提交到数据库之前(完成事务之前),另一个事务 B,读取了对应的数据;

此时 这个 B 读到的数据都是一些临时结果,后续可能马上就被 A 给改了,此时 B 的读取行为就是 "脏读"

这个问题好解决:

张三同学 和 李四 约定好,在提交到数据库之前,李四不要去看该代码,等到提交到数据库之后,再去看看!!!

给读操作加锁(提交之前 不允许随便去读了啊,如果要想读,那就要去向 张三同学/A 申请)

相当于降低了并发程度,降低了效率,提高了隔离性。

                                                                                                                                                  

                                                                                                                                                  

2)不可重复读

事务A提交了之后,事务B才开始读(读是加锁了),然后在B的执行过程中,A又开始了一次,修改了数据;

此时,B执行中,两次读取操作,结果可能不一致,这个就叫做 "不可重复读"

                                                                                                                                                                                                                                                                                                    

如何解决上述问题: 

来进行重新约定:

  1. 张三同学提交之前,李四不要去读(之前的加锁)
  2. 李四读的时候,张三同学不要去改代码

 

因此,隔离性又提高了,并发性又降低了,数据更准确了,效率又更低了 

                                                                                                                                                                                                                                                                                              (3)幻读

闲着也是闲着,张三同学 在 李四 读代码的时候,又开始改别的代码;

李四 在读 student类的代码,张三就在改 teacher类的代码

但是,这里又出现了一个问题,如果 teacher类 本来就存在,也就罢了;

如果是在李四读的过程中,张三新增了一个 teacher类,或者是删除了一个已有的内容,就会产生 "幻读" 问题

事务B读取过程中,事务A进行了修改,没有直接修改B读取的数据,但是 却影响到了B读取的结果集

事务B两次读取到的结果集不一样

这个就叫做 "幻读",相当于是 "不可重复读"的一种特殊情况

解决 "幻读"问题,核心思路就是 "串行化",

严格要求,李四 在读代码的时候,张三不要去修改任何东西,保证读和写操作都是严格串行执行的(串行:一个执行完,才能执行另一个)

隔离性最高,并发程度最低,数据的准确性最好,同时效率最慢

为啥要并发 —— 效率!!!

为啥要隔离 —— 准确!!!

两者一般情况下是相悖的

实际使用的时候,就需要根据实际场景,来决定如何选择档位(看场景对于 性能 比较敏感,还是对于 准确性 比较敏感) 

如:转账操作,一分钱都不能差,慢点没事,一定要稳

       B站之类的,大博主 浏览数/点赞数......这些对于准确性不是很高

MySQL 里提供了 4 个档位,可供自由选择:

1.read uncommitted               并发能力最强,隔离性最弱
2.read committed                   只能读取提交之后的数据,解决了 "脏读"问题
3.repeatable read                  针对读和写都限制了,解决了不可重复读问题
4.serializable                          严格的串行执行,解决了 "幻读"问题

                                                                                                                                                  

1 —> 4,并发能力逐渐减弱,隔离性逐渐增强

我们可以根据实际需要,在配置文件里面,修改数据库的隔离级别(配置文件是之前演示过的 MySQL修改字符集的那个 my.ini 里)

默认的是第3个隔离级别,解决了 "不可重复读"问题


2.4 事务的使用

使用步骤:

  1. 开启事务:start transaction;
  2. 执行多条SQL语句
  3. 回滚或提交: rollback/commit;

说明: rollback 即是全部失败, commit 即是全部成功。

注意:在实际开发的时候,很少通过SQL代码来写事务,更多的是借助其他编程语言;

后续

总结

这就是MySQL数据库 索引和事务的内容啦下一篇就是 MySQL数据库 JDBC编程 部分的内容了

如果这篇博客给你带来了收获可以留下一颗小小的赞吗

  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值