【数据库必备知识】索引和事务

news2024/10/6 1:37:11

数据库系列文章 

1. 零基础带你快速上手SQL语言
2. 玩转表及其数据
3. 上手表设计

4. 索引和事务

目录

📖前言

1. 索引

1.1 索引的概念

1.2 索引的作用

1.3 索引的使用场景

1.4 索引的使用

1.5 索引背后的数据结构(B+树)

2. 事务

2.1 事务的概念

2.2 数据库使用的经典场景

2.3 事务的使用 

2.4 事务的特性

2.5 并发执行事务时可能会出现的问题 

2.5 数据库中的事务隔离级别 

🎉小结ending


📖前言

本文讲解的是数据库中非常重要的知识, 也是面试中会场问到的问题 ---- 索引和事务

1. 索引

1.1 索引的概念

索引是一种特殊的文件, 包含着对数据表里所有记录的引用指针. 可以对表中的一列或多列创建索引, 并指定索引的类型, 各类索引有各自的数据结构实现. 索引存在的意义, 就是为了加快查找的速度, 因为使用索引, 便减少了遍历的步骤.

我们可以将索引理解为一本书的目录, 当我们想查找书中某个内容时, 直接通过目录翻到指定页面即可, 而省去了逐页翻书查找的步骤, 这样便加快了我们查找的速度.

1.2 索引的作用

  • 数据库中的表、数据、索引之间的关系,类似于书架上的图书、书籍内容和书籍目录的关系。
  • 索引所起的作用类似书籍目录,可用于快速定位、检索数据。
  • 索引对于提高数据库的性能有很大的帮助。

不过在使用索引中, 查找速度是变快了, 但是也付出了一定的代价.

  1. 需要付出额外的空间为代价, 来保存索引数据.
  2. 索引可能会拖慢新增, 删除, 修改的速度.

举例子来讲就是, 当书籍内容很多时, 目录的内容也会很多, 光目录就会占有几十页的空间, 当我们在写一些计划书或者论文时, 正文内容是会不断修改的, 目录随之也得不断修改.

当然, 索引总体来说, 还是利大于弊的, 因为在实际开发中, 查询场景往往比增删改查场景频繁很多, 所以我们仍然会选择牺牲一些空间, 来换取时间上的优势.

1.3 索引的使用场景

要考虑对数据库表的某列或某几列创建索引, 需要考虑以下几点:
  • 数据量较大时, 且经常对这些列进行条件查询.
  • 该数据库表的插入操作, 及对这些列的修改操作频率较低.
  • 索引会占用额外的磁盘空间. 

满足以上条件时, 考虑对表中的这些字段创建索引, 以提高查询效率. 反之, 如果非条件查询列, 或经常做插入, 修改操作, 或磁盘空间不足时, 不考虑创建索引.

1.4 索引的使用

在讲使用之前, 先告诉大家一个知识点, 创建主键约束(Primary Key), 唯一约束(Unique), 外键约束(Foreign Key)时,都会自动创建对应列的索引。

1.4.1 查看索引

语法:

show index from 表名;

示例: 查看student表的索引.

show index from student;

可以看到, 由于创建 student 表时, id列为主键, 所以自动创建了名为Primary的索引 

1.4.2 创建索引

语法:

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

示例: 创建学生表中, name字段的索引, 叫做index_student_name. 

create index index_student_name on student(name);

 可以看到, 在student表中, 我们根据name列, 又创建了一个索引出来.

大家要注意, 使用创建索引操作, 可能会很危险, 如果表里的数据特别多, 这个建立索引的操作, 开销是会很大的. 那我们该如何避免该操作呢? 好的做法应该是, 在建表之处, 就提前规划好索引该创建哪些, 这样就不会在中途有很多数据的时候, 临时创建索引了.

1.4.3 删除索引

语法:

drop index 索引名 on 表名;

示例: 删除学生表中, 叫做index_student_name的索引.

drop index index_student_name on student;

 可以看到, 我们之前创建的索引, 已经被删掉了.

删除索引和创建索引类似, 也是有可能存在危险的操作.

1.5 索引背后的数据结构(B+树)

索引使用的操作很容易, 但是我们要理解其背后的数据结构, 在我们之前学习过的数据结构当中, 有哪些数据结构是能加快我们的查找速度呢? 

  • 哈希表, 说到加快查询速度的数据结构, 我们无法避免的就是哈希表, 哈希表的插入和查询操作的时间复杂度可以到O(1), 虽然哈希表的查找很快, 但是索引背后的数据结构并不是哈希表. 哈希表存在一个问题, 它无法支持范围查询(between and), 也无法支持模糊匹配(like).
  • 二叉搜索树, 改进之后的二叉搜索树(红黑树), 其时间复杂度能达到O(logN), 但是它也不适合做为支撑索引建立的数据结构, 为什么呢? 因为当树中元素变多时, 树的高度也会越来越高, 而树的高度就可以相当于元素比较次数, 由于数据库的数据都是存放在磁盘中的, 每向孩子结点访问一次, 便会发生一次磁盘IO, 所以当树的高度越高, 进行查询比较的时候, 访问此盘的次数就越多, 这样便会影响我们操作的整体性能.

那么, 什么数据结构能完美的解决我们这些问题呢? 答案就是B+树, B+树是为了数据库索引, 而量身定做的数据结构. 我们先了解B树, 再了解B+树.

1.5.1 B树

B树可以认为是一颗N叉搜索树, 它与二叉搜索树不同的点就是, 它每个结点不止有2个孩子结点, 而是根据结点中存储的数据来决定孩子结点数的.

 我们可以规定每⼀个节点可以存多少个元素,当节点中达到了规定的元素个数时,才去调整树.

B树就是将数据都划分了范围, 该图中父亲结点存储了四个数据分别为30, 40, 50, 60, 其就有5个孩子结点分别用来存储小于30的数据, 大于30并且40的数据, 大于40并且小于50的数据, 大于50并且小于60的数据, 大于60的数据. 而其孩子结点也同理.

与二叉搜书树相比较来说, B树的每个结点的子树更多, 节点上保存的key值也多了, 意味着在同样key的个数的前提下, B树的高度就要比二叉搜索树的高度低很多.

不过我们索引使用的数据结构并不是B树, 而是它的改进版 ---- B+树

1.5.2 B+树

B+树做为B树的改进版, 他改进了哪里呢? 给大家看一颗B+树.

  可以看到, B+树当中的数据有重复出现的, 那是因为, B+树中的每一个结点中存储的最大数据, 便是该结点范围中的最大值. 所以整个树的所有数据都会包含在叶子结点中的(所有非叶子结点中的数据, 也都会出现在叶子结点中).

😶B+树的特点:

  1. 一个结点, 可以存储N个数据, N个数据又划分出了N个区间(B树会划分N+1个区间).
  2. 每个结点中的数据, 都会在子节点中也存在(同时该数据是其子节点中的最大值).
  3. B+树的叶子结点, 首位相连, 类似于一个链表.
  4. 由于叶子结点, 是完整的数据集合, 只需要在叶子结点存储数据表中每一行的详细数据即可, 而非叶子结点, 存储索引值本身即可, 并不用详细存储数据内容是什么.

😶B+树的优势:

  1. 当前一个结点可以保存更多的数据, 最终树的高度也是相对更矮的, 查询的时候减少了磁盘IO访问次数(原理和B树相同).
  2. 具有稳定性, 所有的查询最终都会落到叶子结点上, 查询任何一个数据, 经过的IO访问次数, 都是一样的.
  3. B+树的所有叶子结点构成一个列表, 此时比较方便程序员进行范围查询. 当查询学号大于5并且小于11的同学, 只需要先找到5所在的位置, 再找到11所在的位置, 然后从5沿着链表遍历到11的位置, 中间所得结果集, 便为查询结果, 十分的高效.
  4. 由于数据都在叶子节点上, 而非叶子结点, 只需要存储索引值, 所以非叶子结点所占空间是比较小的, 这些非叶子结点就可能在内存中缓存一部分, 进一步减少了磁盘IO次数

1.5.3 补充: 回表

请大家思考一个问题, 当我们一个数据表中, 存在多个索引时, 比如 student 表中, 针对 id 有主键索引, 针对 name 又有一个索引时, 其数据是如何构建出来的呢?

这时表的数据还是按照 id 为主键, 构建一个B+树出来, 通过叶子结点组织所有的数据行. 其次, 针对 name 这一列, 也会构建一个B+树, 但是这个B+树的叶子结点跟非叶子结点一样也不会再存储这一样的完整数据, 而是寸主键 id 的值. 此时, 如果根据 name 来查询, 查到叶子结点时, 得到的只是主键 id 的值, 还需要再通过主键 id 的值去, 根据主键够贱的B+树里再查一遍(相当于查了两次B+树). 上述过程便称为回表, 整个过程, 在MySQL中, 都是MySQL自动完成的, 用户感知不到.

2. 事务

2.1 事务的概念

事务是指逻辑上的一组操作, 组成这组操作的各个单元, 要么全部成功, 要么全部失败. 在不同的环境中, 都可以有事务. 对应在数据库中, 就是数据库事务.

数据库事务是指一系列的数据库操作,这些操作被视为单个逻辑单元,必须全部完成或者全部撤销。在事务的执行过程中,如果任意一个操作失败,整个事务都必须回滚,恢复到执行事务之前的状态,保证数据库的一致性和完整性。在数据库应用中,事务通常是为了确保数据的完整性、一致性和可靠性而使用的。一些常用的应用包括银行交易、航班预订系统、电子商务等。

2.2 数据库使用的经典场景

我们来讲一下数据库事务中的经典问题 ---- 银行的转账问题.

现在我们有两个账户, 小张和小王, 其数据都存放在 account 表中.

account
namesavings
小张1000
小王0
# 小王给小张转账500元
# 1. 小王先减500元
update account set savings = savings - 500 where name = '小王';
# 2. 小张再加500元
update account set savings = savings + 500 where name = '小张';

我们假设, 在执行转账的过程中, 执行完操作1后, 数据库崩溃了, 此时这个转账就出现问题了, 因为小王的钱减了, 但是小张却没加钱.

而事务就是为了解决上述问题而产生的概念, 本质上就是将多个SQL语句打包为一个整体, 要么全部执行成功, 要么就一个都不执行(并不是真的没有执行, 而是看起来像是没执行一样, 是因为在执行出错之后, 选择了恢复, 把数据还原到执行前的样子, 这种操作, 叫做回滚rollback), 这样就不会出现只 "执行一半" 的尴尬场景了. 

如果将以上两部操作成为一个事务, 当第一个SQL语句执行结束后, 数据库崩溃, 当下次数据库重新启动后, 就会把上次修改一半的数据给自动还原(转账出现了错误, 将小王转出去的钱给加回去), 进行回滚的时候, 怎样就能知道数据库操作前的状态呢? 数据库当中有一个专门的日志用来记录事务, 正因为如此, 使用事务的时候, 执行SQL的开销会变大, 效率也会变低, 但是提高了数据准确性.

2.3 事务的使用 

使用事务的步骤主要是以下三步:

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

注: commit是全部成功, rollback是全部失败. 

# 小王给小张转账500元
# 1. 开启事务
start transaction;

# 2. 执行多条SQL语句
# 小王先减500元
update account set savings = savings - 500 where name = '小王';
# 小张再加500元
update account set savings = savings + 500 where name = '小张';

# 提交事务 
# 到这一步,相当于事务就执行完了
commit;

2.4 事务的特性

 事物的四大特性是面试中的经典题目, 请同学们务必记住:

  • 原子性 (Atomicity): 指整个事务中的所有操作要么全部成功, 要么全部失败回滚, 不允许出现部分成功或部分失败的情况. 

  • 一致性 (Consistency): 指事务开始之前和结束之后, 数据库的状态必须是一致的, 即满足所有的约束条件和完整性规则.

  • 隔离性 (Isolation): 指事务的执行不受其他事务的干扰, 一个事务执行过程中的中间状态对其他事务是不可见的. 

  • 持久性 (Durability): 指事务一旦提交, 对数据库的修改将永久保存到数据库中, 即使出现宕机等故障, 也不会丢失数据. 

其中事务的隔离性, 其实就是为了解决 "并发" 执行事务, 而引出的一些问题. 数据库也是服务器, 就有可能有多个客户端给服务器提交事务, 这时数据库就需要同时处理处理多个客户端的事务, 这就叫做并发.

接下来就说一说, 并发处理事务, 可能有哪些问题, 以及这些问题, 数据库的隔离性是怎样给解决的.

2.5 并发执行事务时可能会出现的问题 

2.5.1 脏读

假设用户A向数据库中的账户表中插入了一条新记录,但是还未提交事务,此时用户B查询账户表发现了这条新记录。但是由于用户A还未提交事务,这条记录实际上还未被确认有效,如果用户A在事务提交之前回滚了该记录,那么用户B查询到的新记录实际上是“脏数据”,这就是脏读。

为了解决脏读问题, 在MySQL中, 引入了 "给操作加锁" 这样的机制, 在本例子中, 就是当用户A向数据库中插入数据时, 给写入操作上锁, 只有当用户A确认提交事务后, 用户B才能查询该数据, 这意味着, 修改操作跟插入操作没法并发了(不能同时执行), 这个给写入操作上锁, 就降低了并发程度(效率变低), 提高了隔离性(数据准确度提高).

2.5.2 不可重复读

假设用户A在一个事务中正在查询账户表中的某个记录,但是此时用户B也开始了一个事务并且对该记录进行了修改,然后用户A再次查询该记录,发现此时该记录已经与之前查询到的不同了,这就是不可重复读。

在本例子中, 我们就可以对读操作进行上锁, 就是当用户A在查询数据时, 用户B不可以修改改数据, 通过对读加锁, 又进一步降低了并发程度, 提高了隔离性.

2.5.3 幻读

假设用户A在一个事务中查询了账户表中某个范围的记录,但是此时用户B插入了一条新记录,这个新记录就像是幻觉一样出现在了该范围内,这就是幻读。例如,A事务查询到了某个部门的所有员工信息,但是在查询过程中,B事务插入了一些新的员工记录,导致A事务查询到的结果集中出现了未查询到的员工信息。

在读加锁和写加锁的前提下, 一个事务两次读取同一个数据, 发现读取的数据值是一样的, 但是结果集不一样, 我们可以使用 "串行化" 这样的方式来解决幻读. 串行化就是彻底放弃并发处理事务, 像糖葫芦串一样一个接一个的串行的处理事务. 这样做, 并发程度是最低的, 效率是最慢的, 隔离性是最高的, 数据准确性也是最高的.

2.5 数据库中的事务隔离级别 

为了处理上述所说的并发处理事务可能发生的三个经典问题, MySQL提供了4种隔离级别, 用来对应上面的几个情况.

  • read uncommitted(读未提交): 没有进行任何锁限制. 并发程度最高, 隔离性最低.
  • read committed(读已提交): 给写加锁. 并发程度降低, 隔离性提高.(解决脏读)
  • repeatable read(可重复读): 给写和读都加锁. 并发程度进一步降低, 隔离性进一步提高.(解决不可重复读)
  • serializable(可序列化的): 串行化. 并发程度最低, 隔离性最高.(解决幻读)

这几个隔离级别该如何选择, 我们需要在准确性和效率之间做权衡, 看实际业务需求, 看业务使用的场景是怎样的来决定. 比如在涉及到钱的转账问题上, 一分钱都是不能错的, 那怕效率差点, 也得保证了钱的准确性. 再比如给一个热门视屏点赞, 来看一个视屏有多少赞, 只要求快, 成千上万的人都在同一时间点赞, 如果一个一个排队来的话, 效率得慢死, 但此场景我们追求的是效率, 赞的数据有十个八个的误差并不关键.


🎉小结ending

✨ 本文主要讲述了数据库当中的索引和事务, 并且花大量篇幅讲解了一下索引背后的数据结构 ---- B+树, 又讲了一下B树和B+树到底是什么, 以及有什么特点和优势.

✨ 想了解更多数据库知识, 可以打开博主的数据库专栏目录↓小白的数据库学习之路http://t.csdn.cn/Fh557✨ 感谢你们的耐心阅读, 博主本人也是一名学生, 也还有需要很多学习的东西. 写这篇文章是以本人所学内容为基础, 日后也会不断更新自己的学习记录, 我们一起努力进步, 变得优秀, 小小菜鸟, 也能有大大梦想, 关注我, 一起学习.

再次感谢你们的阅读, 你们的鼓励是我创作的最大动力!!!!!

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

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

相关文章

Centos7安装Python3.10

Centos7用yum安装的Python3版本比较旧,想要安装最新版本的Python3需要自己动手编译安装。下面就来讲讲安装步骤,主要分为这么几个步骤,依赖→下载→编译→配置。另外所有操作都是在root用户下进行。 依赖 编译Python源码需要依赖许多库&…

spring.cache 随笔0 集成设计

0. 最近感觉 “困意驱动睡眠” 也有他的意义 spring cache学习(一):spring cache注解简单了解 Java Caching JSR107介绍 同样,本章也会简单的集成redisson作为缓存服务 1. 从我们自己写的javaConfig开始吧 Configuration // 这…

Java——文件操作

文件操作 1、File类概述2、File类的常用APIFile类的判断文件类型、获取文件信息功能创建文件、删除文件功能遍历文件夹文件搜索 3、字符集常见字符集字符集的编码、解码操作 4、IO流分类5、字节流的使用文件字节输入流文件字节输出流文件拷贝 6、字符类的使用文件字符输入流文件…

“前端已死”

一、一些迹象 逛社区,偶然看到了这张图片: 嗯……我眉头一皱,久久不语,心想,有这么夸张吗,假的吧? 突然想到,最近我在社区发了个前端招聘的信息,结果简历漫天纷飞&…

【C++】auto_ptr为何被唾弃?以及其他智能指针的学习

搭配异常可以让异常的代码更简洁 文章目录 智能指针 内存泄漏的危害 1.auto_ptr(非常不建议使用) 2.unique_ptr 3.shared_ptr 4.weak_ptr总结 智能指针 C中为什么会需要智能指针呢?下面我们看一下样例: int div() {int a, b;cin >&g…

图表制作办公首选--实用图表工具Echars

实用图表工具Echars 前言 由于工作的需要,在写材料的时候需要使用到柱状图、饼状图、折线图等等展示数据,可以使用PPT等办公软件构建出图表,在这里可以使用更加方便、更加美观的工具Echars。 Echars图表使用 Echars官网:Ecahr…

二叉平衡树之红黑树

目录 1.概念 2.性质 3.节点的定义 4.插入 1.按照二叉搜索树规则插入结点 2.调整颜色 1.uncle存在且为红色 2.uncle不存在或者为黑 cur为 3.根节点改为黑色 5.验证 6.比较 7.应用 1.概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存…

【计算机网络】计算机网络期末自测题(一)

目录 一、 填空题:(20 分,每空 1 分) 二、 选择题(20 分,每小题 1 分) 三、不定项选择题 (10 分,每小题 1 分) 四、名词解释 (15 分,每小题 3 分) 五、简答题 (25 分) 得分 一、 填空题:(20 分&#xff…

【C++】STL——string类详解

🚀 作者简介:一名在后端领域学习,并渴望能够学有所成的追梦人。 🚁 个人主页:不 良 🔥 系列专栏:🛸C 🛹Linux 📕 学习格言:博观而约取&#xff0…

混合策略改进的哈里斯鹰优化算法-附代码

混合策略改进的哈里斯鹰优化算法 文章目录 混合策略改进的哈里斯鹰优化算法1.哈里斯鹰优化算法2.改进哈里斯鹰优化算法2.1 初始化种群的改进2.1.1 初始种群多样化2.1.2 初始种群精英化 2.2 逃逸能量递减机制的改进2.4 拉普拉斯交叉算子策略 3.实验结果4.参考文献5.Matlab代码6.…

6.17 、Java初级:锁

1 同步锁 1.1 前言 经过前面多线程编程的学习,我们遇到了线程安全的相关问题,比如多线程售票情景下的超卖/重卖现象. 上节笔记点这里-进程与线程笔记 我们如何判断程序有没有可能出现线程安全问题,主要有以下三个条件: 在多线程程序中 有共享数据 多条语句操作共享数据 多…

移动web-渐变

渐变 使用场景:使用background-image属性实现渐变背景效果 代码:background-image: linear-gradient(参数1,参数2,参数3...); (默认的方位从上到下) 参数1 方位名词: to right, to left 角度deg: 直接写度数 参数2 颜色1 参数3 颜色2... 注意&#xff…

看完这篇 教你玩转渗透测试靶机vulnhub—Corrosion:1

Vulnhub靶机Corrosion:1渗透测试详解 Vulnhub靶机介绍:Vulnhub靶机下载:Vulnhub靶机安装:Vulnhub靶机漏洞详解:①:信息收集: Vulnhub靶机渗透总结: Vulnhub靶机介绍: vulnhub是个提…

canvas详解01-绘制基本图形

既然我们已经设置了 canvas 环境,我们可以深入了解如何在 canvas 上绘制。到本文的最后,你将学会如何绘制矩形,三角形,直线,圆弧和曲线,变得熟悉这些基本的形状。绘制物体到 Canvas 前,需掌握路…

软件工程——第5章总体设计知识点整理

本专栏是博主个人笔记,主要目的是利用碎片化的时间来记忆软工知识点,特此声明! 文章目录 1.总体设计的基本目的? 2.总体设计的任务? 3.总体设计过程由哪两个阶段组成? 4.总体设计的步骤? 5…

【Linux从入门到精通】进程地址空间(虚拟地址 vs 物理地址)

本篇文章会围绕三个问题(什么是地址空间?地址空间是如何设计的?为什么要有地址空间?)进行展开讲述。其中主要是了解虚拟地址和物理地址的区别。希望本篇文章会对你有所帮助。 文章目录 一、什么是地址空间?…

《机器学习公式推导与代码实现》chapter6-k近邻算法

《机器学习公式推导与代码实现》学习笔记,记录一下自己的学习过程,详细的内容请大家购买作者的书籍查阅。 k近邻算法 k近邻(k-nearest neighbor, k-NN)算法是一种经典的分类算法。k近邻算法根据新的输入实例的k个最近邻实例的类别来决定其分类。所以k近…

rust abc(1): 最小环境搭建

文章目录 1. 目的2. 命令集合3. 安装或更新 rust3.1 命令3.2 运行结果 4. 包管理工具 Cargo5. 创建 Rust 的 Hello World 程序: 单个文件6. 创建 Rust 的 Hello World 工程: 基于 Cargo6.1 cargo new 创建工程6.2 cargo run6.3 完整输出6.4 解释 7. IDE/编辑器8. Re…

Jetson安装Anaconda(miniforge3)

1 miniforge3 miniforge集成了Anaconda的核心工具:conda。conda是一个包和环境管理工具。因此, miniforge里面的conda和Anaconda里面的conda完全一样;你能用Anaconda做的安装、升级、删除包等功能,miniforge都能做;你…

angular实现自定义模块路由懒加载;配置自定义模块路由及子路由

图片中绿色表示新建的文件;黄色表示被更改的文件; 1、创建一个新的项目 ng new angularlazyload2、创建一个用户模块,并配置路由 ng g module module/user --routing如图: 3 、在module/模块下创建user组件 ng g component module/user如图: 4、实现路由懒加载 依次…