【MySQL初阶】索引与事务

1. 索引

1.1 索引基本概念

1.1.1 索引介绍

索引(index):是一种特殊的文件,包含着对数据表里所有记录的引用指针。可以对表中的一列或者多列创建索引,并指定索引的类型,各类索引有各自的数据结构实现。(具体细节在MySQL进阶章节详细讨论)

在数据库中,使用条件查询时需要遍历表,相当于O(N)的时间复杂度,但是数据库中的数据是存储在硬盘上的,而数据结构中的O(N)是基于内存的角度谈论的,所以硬盘I/O操作遍历操作更加缓慢!

而索引的目的就是提高 “查询效率” ,考虑有一本书,如何能够快速的找到某个章节的页码,这个时候就需要借助目录了 ,而索引的功能就类似于目录,能够提高查询效率。
索引特点

  1. 索引能够加快查询效率
  2. 索引自身也是一定的数据结构组成,也要占据相应的存储空间
  3. 当我们进行新增、删除、修改操作时,不仅需要修改数据,同时也要对索引进行维护管理

总结:因此索引适用的场景需要具备如下两大条件:1、对于存储空间要求不高(存储空间充裕);2、应用场景以查询居多,增加、修改、删除等频率不高

1.1.2 索引相关SQL操作

1.1.2.1 查看索引

语法格式:show index from 表名;

create database blog_mysql_index;
create table t_user(username varchar(20) primary key,`password` varchar(20) not null);
show index from t_user;

结果
image.png
从中我们可以发现表中具有哪些索引,以及哪些列上加上了索引,并且我们可以发现某些约束例如 primary keyunique 等频繁用于查询操作,所以会自动加上一些索引

1.1.2.2 新增索引

语法格式:create index 索引名 on 表名(列名);

create index index_password on t_user(`password`);
show index from t_user;

结果
image.png
从中我们可以发现列password也加上了索引。需要注意的是,创建索引这个操作是一个危险操作!如果表中数据量比较少不会产生问题,但是如果数据量非常庞大,这个时候添加索引就会导致数据结构重新组织,此时就会触发大量的硬盘I/O,数据库服务器很容易就宕机了!

1.1.2.3 删除索引

语法格式:drop index 索引名 on 表名;

drop index index_password on t_user;
show index from t_user;

结果
image.png
同理,删除索引也是一个十分危险的操作!所以尽量在建表之初就确定好哪些字段需要加上索引,而不要等到生产环境上线数据量庞大之后再考虑索引的问题。

但是实际情况由于需求的不断变化,因此很难项目之初就确定好,所以事实上程序员可以通过"曲线救国"的方式处理索引问题,那就是使用新的机器部署数据库,然后建表建索引,逐步将原环境上的数据拷贝到新数据库中,最后用新的机器代替旧的机器就可以了!

1.2 索引底层数据结构

我们需要关心索引底层数据结构的实现,但是我们此处也是简单介绍(详细内容在数据库进阶或者高阶数据结构部分介绍)

前面提到索引本身实际上就是通过额外的数据结构来对表中的数据进行重新组织,那么我们需要考虑使用什么样的数据结构才能在时间、空间上占据优势呢?回忆下我们之前学习的常见数据结构有顺序表、链表、栈、队列、二叉树、哈希表,其中顺序表、链表、栈、队列显然是不适合用于"查找"功能的!而哈希表通过一定时间扩容是可以实现平均时间复杂度为O(1)的,但是哈希表的原理是通过哈希函数计算得出存储下标进行查找,而数据库中很多操作并不是单纯比较相等,例如between and范围比较就无法使用哈希表!所以此处最适合的还是平衡二叉树这样的数据结构(时间复杂度为O(logN))

1.2.1 Java中的ArrayList与LinkedList的区别(常见面试题)

个人整理:

  • 针对ArrayList来说,它的底层实现是数组,具有随机访问特性,随机访问的时间复杂度是O(1),ArrayList尾插/尾删较快(时间复杂度都是O(1)),而在头插/头删/中间节点插入/中间节点删除的平均时间复杂度是O(N)
  • 针对LinkedList来说,它的底层实现是基于链表的,不支持随机访问,进行头插/头删/尾插/尾删的时间复杂度是O(1),中间节点插入/删除的时间复杂度是O(N)
  • LinkedList相较于ArrayList的唯一优势就是可以支持头插头删,因此可以用来轻松实现队列这样的数据结构,除此以外,其他方面大多数都是ArrayList占据优势

常见错误说法

  1. 使用LinkedList占用空间比ArrayList少,因为ArrayList需要预分配好空间大小,容易浪费

    LinkedList中的节点不止存放数据,也需要其他空间用于存放指针域,所以具体的存储空间大小不一定!

  2. LinkedList的遍历速度快于ArrayList

    这也是错误的,链表访问下一个元素需要通过next指针引用,相比于ArrayList的i++操作要多一次访存操作,而i++通常会优化到寄存器

  3. LinkedList的中间节点插入的时间复杂度是O(1)

    正确答案应该是O(N),这是Java的接口设计失误导致的!事实上C++通过迭代器的方式可以实现O(1)时间复杂度,但是Java的插入就是通过遍历找节点的方式

1.2.2 B+树

数据库的索引使用了B+树这样的数据结构,可以说B+树像是专门为数据库这样的场景量身定制的数据结构了,要想理解B+树,我们需要先了解它的前身——B树(也被写做B-树)

1.2.2.1 B-树

B-树:是一颗N叉搜索树(有序),是对于二叉搜索树的扩展,一个节点可以包含N个key值,这N个值又划分出了N+1个区间,如下图所示:
image.png
因此相较于二叉搜索树来说,相同高度的B树可以表示的数据个数更多了,使用B树来查询的时候,如果单论比较次数确定比二叉搜索树多很多,但是关键在于同一个节点的多个key值可以通过一次硬盘IO读取,即使总的比较次数增加了,但是硬盘IO次数少了,显著提高了效率!

1.2.2.2 B+树

B+树:B+树就是在B-树的基础上又做出了改进,同样也是N叉搜索树,每个节点可以包含多个key值,N个key可以划分出N个区间,B+树如图所示:
image.png
B+树的特点

  1. N叉搜索树,一个节点包含N个key值,N个key值划分出N个区间
  2. 每个节点的N个key中,设定一个最大值(或最小值)
  3. 每个节点的N个key值都会在子树中重复出现
  4. 把叶子节点通过 链式结构 相连

B+树的好处

  1. 针对范围查询比较有利,例如查询21 <= age <= 37的所有人群,只需要在B+树中找到叶子节点中的21然后沿着链表往后一直遍历到37即可,得益于该链式结构,就省去了对树进行回溯查找的麻烦了
  2. 查询时间以及IO次数更加稳定,查询所有元素都需要经过根节点直到叶子节点的过程,所以途经的硬盘IO次数是固定的,更加稳定可预测!
  3. 由于叶子节点是数据的全集,因此非叶子节点为了节省内存空间可以只存储对应的key值缓存而不存储具体元素内容,大幅度减少了硬盘IO的次数

2. 事务

2.1 事务的相关概念

事务:事务是一组逻辑操作,这些操作要么全都执行成功,要么全都不执行,事务可以在不同环境中使用,在数据库中就称之为"数据库事务"

2.2 事务基本特性(经典面试题)

事务具有以下四大特性(简称ACID):

  1. 原子性:通过事务将多个操作打包在一起,要么全都执行,要么都不执行
  2. 一致性:相当于原子性的延申,数据库状态总是从一个一致性状态向另一个一致性状态转变的,不可能存在例如转账业务中钱凭空消失这样不科学的情况
  3. 持久性:事务的任何修改操作,都是会持久化存在的(存入硬盘)
  4. 隔离性:多个事务并发执行时,可能会引入一些问题,通过隔离性以及隔离级别的设置可以有效权衡其中的问题

由于数据库是一个基于客户端/服务器(C/S架构)的程序,因此如果多个客户端向服务器提交事务请求,就会出现事务并发执行的情况,如果处理的是同一个数据,就可能会引入问题,下面就来讨论几种常见的问题:
典型bug1:脏读问题
考虑这样一个场景,当前有存在两个事务:事务t1,事务t2,其中事务t1对成绩表中姓名为张三的同学成绩修改为59,此时事务t2并发执行读取同一张成绩表中名为张三的成绩为59,但是此时事务t1发现有一个分数忘记统计了,因此再次修改张三同学的成绩为60,那么现在问题来了,如果事务t2需要根据成绩登记是否挂科,那就出大问题了!即存在两个事务,事务t1修改数据,事务t2读取数据,可能事务t1后续仍需要再次修改数据,t2此时读取的就是一个"脏数据",这就被称为 “脏读问题” ,而解决脏读问题就要对"写操作"加锁,即事务t1在修改数据的过程中,其他事务无法进行读取操作
典型bug2:不可重复读问题
此时我们规定对"写操作"加锁,因此不会出现脏读问题,再次考虑这样一个场景,事务t1对张三的成绩修改为59(此时其他事务无法读取或修改),当事务t1执行完毕后,事务t2读取张三成绩为59,由于t2事务为读取操作,其他事务可以并发执行,此时事务t3修改张三成绩为60,此时问题又出现了!这样的情况就是**“不可重复读”** ,解决"不可重复读"问题的关键就在于给"读操作"加锁,当事务t2读取数据时,其他事务无法修改同样的数据
典型bug3:幻读问题
此时我们规定对"写操作"加锁、对"读操作"加锁,因此不会出现"脏读"、"不可重复读"问题,再次考虑这样一个场景,事务t1读取张三成绩时,事务t2新增了一个学生的成绩,此时由于修改的不是同一个数据所以不会触发"不可重复读"这样的问题,但是对于事务t2来说,整体的数据集合仍然发生了变化,这种情况就叫做 “幻读” ,解决"幻读"问题就需要让事务完全"串行化"执行,即不采取并发执行操作,严格按照执行事务t1,然后再执行事务t2,最后执行事务t3的顺序
总结:上述这些情况是否真的算是"bug"是要针对不同的业务场景进行定义的,归根到底需要根据实际情况判断是追求数据的可靠性还是效率!MySQL针对不同情况为我们提供了不同的隔离级别:

  1. read uncommited:读未提交,并行程度最高、隔离程度最低、数据最不可靠、效率最高,此时可能出现脏读+幻读+不可重复读问题
  2. read commited:读已提交,相当于给"写操作"加锁,此时并行程度降低、隔离级别变高、数据更加可靠、效率降低一些,可能会出现不可重复读+幻读问题
  3. repeatable read:可重复读,相当于给"读操作"加锁,此时并行程度进一步降低、隔离级别进一步升高、数据可靠性进一步提升、效率进一步降低,可能会出现幻读问题
  4. serializable:串行化执行,让所有的事务串行顺序执行,并行程度最低、隔离级别最高、数据最可靠、效率最低

其中MySQL的默认级别为repeatable read可重复读

2.3 事务的基本使用

事务在数据库中可以通过如下几个命令进行操作:

  1. 开启事务

    语法格式:start transaction;

  2. 事务回滚

    语法格式:rollback;

  3. 事务提交

    语法格式:commit;

代码示例

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_user values ('qwe','123');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t_user values ('abc','456');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t_user;
+----------+----------+
| username | password |
+----------+----------+
| abc      | 456      |
| qwe      | 123      |
+----------+----------+
2 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from t_user;
Empty set (0.00 sec)

mysql> insert into t_user values ('qwe','123');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t_user values ('abc','456');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t_user;
+----------+----------+
| username | password |
+----------+----------+
| abc      | 456      |
| qwe      | 123      |
+----------+----------+
2 rows in set (0.00 sec)

mysql>

image.png
总结:事务在数据库中是一大核心机制,是用来保证数据可靠性的,但是我们往往不会在数据库命令行中开启事务,往往是搭配某一门编程语言在业务中使用的,例如Java的Spring框架就封装了事务管理,当程序抛出异常时可以考虑回滚机制来确保数据的可靠性!事务回滚机制实现方式既跟undo log、redo log有关,也跟背后的存储引擎有关,会在后续数据库进阶章节进行讨论!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯DP算法——区间DP(C++)

根据题意要求的是将石子合并的最小权值&#xff0c;我们可以根据DP思想使用二维数组f[i,j]来存放所有从第i堆石子到第j堆石子合并成一堆石子的合并方式。 然后由第二个图所示&#xff0c;我们可以将i到j区间分成两个区间&#xff0c;因为将i到j合并成一个区间的前一步一定是合…

DecBBox(Decode Bounding Box)的软件实现

在深度学习中&#xff0c;"decbbox" 通常指的是 "Decode Bounding Box"&#xff0c;即解码边界框。这是在目标检测任务中常见的一个步骤&#xff0c;用于将网络输出的边界框参数&#xff08;通常是相对于某种参考框的偏移量或者缩放参数&#xff09;转换为…

ico图标是什么意思?ico图标怎么生成?如何在线制作ico图标?

我们在浏览器浏览网页时或收藏某网页时&#xff0c;经常看到有些网页标题前面有一个图标&#xff0c;有些是logo&#xff0c;有些是其他图标&#xff0c;其实这种图标就是网站的favicon.ico图标&#xff0c;也就是我们平时大家所说ico图标。 什么是favicon.ico图标&#xff1f…

贪心/树形dp

思路&#xff1a; 因为如果红色节点的子树中如果有红色节点的话&#xff0c;那么该子树对其不会造成影响&#xff0c;不用考虑&#xff0c;因此我们在考虑每个红色节点时&#xff0c;不考虑其红色子树。那么如图&#xff0c;对每个红色节点答案有贡献的就是其所有非红色子节点…

一个project作为另一个project的Module

android如何引入另一个工程,Android studio 一个项目引入另一个项目作为Libary-CSDN博客 1.file-new-import module 2.

mysql 分表实战

本文主要介绍基于range分区的相关 1、业务需求&#xff0c;每日160w数据&#xff0c;每月2000w;解决大表数据读写性能问题。 2、数据库mysql 8.0.34&#xff0c;默认innerDB;mysql自带的逻辑分表 3、分表的目的:解决大表性能差&#xff0c;小表缩小查询单位的特点(其实优化的精…

不做内容引流,你凭什么在互联网上赚钱?

孩子们放寒假了&#xff0c;待在家里不是看电视&#xff0c;就是拿着手机刷视频&#xff0c;脸上是各种欢快和满足。只是一切换到写作业模式&#xff0c;孩子是各种痛苦表情包&#xff0c;家长则是使出浑身解数&#xff0c;上演亲子大战。可见娱乐常常让人愉悦&#xff0c;而学…

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(4)-Mongo数据仓储和工作单元模式封装

前言 上一章我们把系统所需要的MongoDB集合设计好了&#xff0c;这一章我们的主要任务是使用.NET Core应用程序连接MongoDB并且封装MongoDB数据仓储和工作单元模式&#xff0c;因为本章内容涵盖的有点多关于仓储和工作单元的使用就放到下一章节中讲解了。仓储模式&#xff08;R…

(done) 什么是特征值和特征向量?如何求特征值的特征向量 ?如何判断一个矩阵能否相似对角化?

什么是齐次方程&#xff1f; https://blog.csdn.net/shimly123456/article/details/136198159 行列式和是否有解的关系&#xff1f; https://blog.csdn.net/shimly123456/article/details/136198215 特征值和特征向量 参考视频&#xff1a;https://www.bilibili.com/video/BV…

基于springboot+vue的在线宠物用品交易网站(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

uni-app 经验分享,从入门到离职(五)——由浅入深 uni-app 数据缓存

文章目录 &#x1f4cb;前言⏬关于专栏 &#x1f3af;什么是数据存储&#x1f9e9;数据存储——存储&#x1f4cc; uni.setStorage(OBJECT)&#x1f4cc; uni.setStorageSync(KEY,DATA) &#x1f9e9;数据存储——获取&#x1f4cc; uni.getStorage(OBJECT)&#x1f4cc; uni.g…

学会如何打印菱形

打印菱形 题目描述&#xff1a;解法思路&#xff1a;解法代码运行结果&#xff1a; 题目描述&#xff1a; 输入⼀个整数n&#xff0c;打印对应2*n-1行的菱形图案&#xff0c;比如&#xff0c;输入7&#xff0c;输出如下图案&#xff0c;图案总共13行 解法思路&#xff1a; …

企业计算机服务器中了crypt勒索病毒怎么办,crypt勒索病毒解密数据恢复

计算机服务器设备为企业的生产运营提供了极大便利&#xff0c;企业的重要核心数据大多都存储在计算机服务器中&#xff0c;保护企业计算机服务器免遭勒索病毒攻击&#xff0c;是一项艰巨的工作任务。但即便很多企业都做好的了安全运维工作&#xff0c;依旧免不了被勒索病毒攻击…

队列的基本操作——常见队列的对比分析(c语言完整代码包含注释)

目录 一、队列 1.1基本概念 1.2基本操作 1.3 队列分类 1.3.1带头队列 1.3.2不带头队列 1.3.3 循环带头队列 1.3.4 循环不带头队列 1.3.5 总结 二、代码实现 2.1带头队列 2.2不带头队列 2.3循环带头队列 2.4循环不带头队列 一、队列 1.1基本概念 队列&#xff08…

RAW 编程接口 TCP 简介

一、LWIP 中 中 RAW API 编程接口中与 TCP 相关的函数 二、LWIP TCP RAW API 函数 三、LwIP_Periodic_Handle函数 LwIP_Periodic_Handle 函数是一个必须被无限循环调用的 LwIP支持函数&#xff0c;一般在 main函数的无限循环中调用&#xff0c;主要功能是为 LwIP各个模块提供…

由于找不到d3dx9_43.dll无法继续执行的解决方法,5种有效的方法

丢失d3dx9_43.dll文件可能会引发一系列运行问题&#xff0c;具体表现在哪些方面呢&#xff1f;首先&#xff0c;它是DirectX 9.0c的一个重要动态链接库文件&#xff0c;对于许多基于此版本DirectX开发的老旧或经典PC游戏至关重要。一旦缺失&#xff0c;可能导致这些游戏无法启动…

element ui 安装 简易过程 已解决

我之所以将Element归类为Vue.js&#xff0c;其主要原因是Element是&#xff08;饿了么团队&#xff09;基于MVVM框架Vue开源出来的一套前端ui组件。我最爱的就是它的布局容器&#xff01;&#xff01;&#xff01; 下面进入正题&#xff1a; 1、Element的安装 首先你需要创建…

基于Java+Selenium的WebUI自动化测试框架(一)---页面元素定位器

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

糖尿病性视网膜病变(DR)的自动化检测和分期

糖尿病性视网膜病变&#xff08;DR&#xff09;的自动化检测和分期 提出背景DR的阶段及其特征 历年解法计算机视觉方法多分类方法 新的解法深度学习方法迁移学习大模型多模型集成全流程分析 总结特征1&#xff1a;图像分割特征2&#xff1a;疾病分级特征3&#xff1a;治疗建议生…

二进制中-1加上+1如果按照原码相加会存在什么问题?

问题描述&#xff1a;二进制中-1加上1如果按照原码相加会存在什么问题&#xff1f; 问题解答&#xff1a; -1加1等于-2&#xff0c;这明显是不对的。 因此引入反码的概念 然后再将计算后反码在取反码&#xff0c;得到-0&#xff0c;如下图所示。 -0不太精确&#xff0c;因此再…