目录
·前言
一、索引
1.索引概述
(1)基本概念
(2)索引作用
(3)索引特点
(4)适用场景
2.索引的操作
(1)查看索引
(2)创建索引
(3)删除索引
3.索引底层数据结构
(1)概述
(2)B树的基本概念
(3)B+树的基本概念
二、事务
1.事务的概念
2.事务的特性
(1)原子性
(2)一致性
(3)持久性
(4)隔离性
3.有关事务典型问题
(1)脏读问题
(2)不可重复读问题
(3)幻读问题
4.隔离级别
(1)read uncommitted
(2)read committed
(3)repeatable read
(4)serializable
5.事务的使用
·尾声
·前言
谈到MySQL,避不开索引与事务这两个十分重要的概念,索引使MySQL在查询时效率更高,事务则是为了MySQL能更安全无误的运行,下面就由我来为大家进行今天的知识介绍吧。
一、索引
1.索引概述
(1)基本概念
索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引, 并指定索引的类型,各类索引有各自的数据结构实现。索引的英文名是index(更多被翻译成下标),可以理解成目录。
(2)索引作用
假设你有一本书,如何快速定位某个章节所在的位置,这就需要使用目录进行查找了,在数据库中,进行条件查询的时候经常需要遍历表,由于数据库是把数据存储在硬盘上,所以在数据库上进行遍历表的操作时间复杂度O(N)会比咱们平时说的O(N)要慢很多,因此我们可以给数据库引入索引,从而提高我们的查询速度。
- 数据库中的表、数据、索引直接的关系,就类似于书架上图书,图书内容和图书目录的关系
- 索引所起的作用就类似于图书目录,可以快速定位、检索数据
- 索引对于提高数据库性能有很大的帮助
(3)索引特点
- 加快查询的速度;
- 索引自身是一定的数据结构,也要占据内存空间;
- 当我们需要进行新增、删除、修改操作的时候,也需要针对索引进行更新(额外开销)。
需要注意的是,进行删除、修改操作时,搭配条件语句,需要先根据条件查找,再进行修改。如果没有使用条件进行查找或者使用条件查找但是没有利用索引的时候,删除、修改操作的速度肯定会慢,并且在修改、删除之后,还需要进行维护索引,这个过程是比较慢的。
(4)适用场景
- 存储空间比较充裕(索引会占用额外的空间);
- 应用场景中,涉及查询较多,增加、删除、修改都不多。(减少维护成本)
对于读多写少的场景,是比较常见的,很多web程序(网站)都是这样的。
满足以上条件,可以考虑对表中的这些字段创建索引,这样可以提高查询的效率,反之,如果使用非条件查询列,或者经常做插入、修改操作,或者磁盘空间不足时,不考虑创建索引。
2.索引的操作
(1)查看索引
语法格式:
show index from 表名;
在前面文章介绍约束时,曾提过创建主键约束(PRIMARY KEY)、唯一约束(UNIQUE)、外键约束(FOREIGN KEY)时会自动创建对应列的索引,下面通过示例进一步介绍与演示: 在一个表中,索引可以有多个,每个索引都是根据某个具体的列来展开的,后续按照这个列进行查询,这个时候才能提高效率。
(2)创建索引
语法格式:
create index 索引名 on 表名(字段名);
创建索引的这个操作是一个比较危险的操作,如果表中没有数据,或者数据比较少,此时创建索引是没有危险的,如果表本身就有很多数据,此时创建索引操作就会触发大量的硬盘IO。创建索引的具体操作与效果如下:
为了减少上述创建索引引起的危险情况,就需要我们在建表之初,做好规划,在创建表时就把需要的索引创建好。
(3)删除索引
语法格式:
drop index 索引名 on 表名;
删除索引也是一个比较危险的操作,逻辑与创建索引逻辑相似,这里演示示例就是将上面刚创建的索引进行删除,具体操作与效果如下:
3.索引底层数据结构
(1)概述
索引其实就是通过额外的数据结构,来针对表里的数据进行重新组织,使用什么样样的数据结构对于查询的时间,表的占用空间都有很大的影响,在学习数据结构时,有一个数据结构在查询时,时间复杂度是O(1),这个数据结构是哈希表,由于自身复杂的实现逻辑,保证了它是查询速度最快的,可是,在数据库查询的时候,经常是指定条件进行查询,进行一些范围查询,这时候使用哈希表就十分不友好了,因为哈希表查询是把key通过一定的hash函数转换成数组下标,再在对应下标中进行查找,这里只能比较相等查询一个数据,因此,数据库的索引使用的是B+树作为数据结构,B+树这个数据结构相当于是针对数据库这个场景量身定做的。
(2)B树的基本概念
再介绍B+树之前,先介绍一下B树的逻辑,因为B+树就是在B树上进行的调整。
B树是一个N叉搜索树,只不过这里要求数据是有序的,B树就是在二叉搜索树这里进行了扩展,一个节点上可能包含N个值,这N个值就划分出了N+1个区间,这样同样高度的树,B树能表示的元素个数就比二叉搜索树多很多很多了,同时使用B树进行查询的时候,每一轮比较次数比二叉搜索树要更多,但是,这里关键在与同一个节点的这些key都是一次硬盘IO就读出来了,所以即使总的比较次数增加了,但是硬盘IO的次数减少了,进行一次硬盘IO相当于内存中进行1万次的比较,由此可以看出B树相比与二叉搜索树更有优势用在数据库的索引上,B树的大致结构如下:
(3)B+树的基本概念
B+树,是在B树的基础上进行了改进,B树同样也是N叉搜索树,每个节点包含多个key,N个key划分出N个区间。
B+树的特点:
- N叉搜索树,每个节点上包含N个key,N个key划分出N个区间;
- 每个节点的N个key中,会存在一个“最大值”(设定成最小值也一样);
- 每个节点中的key,都会在子树中重复出现;
- 把叶子节点之间使用链式结构进行相连。
B+树大致结构如下:
B+树的优点:
- B+树每个节点中的key,都会在子树中重复出现,这一特性中,“重复出现”带来一个好处,就是所有数据都包含在叶子节点这一层中,这样叶子节点就有着数据全集,并且B+树的叶子节点之间使用链式结构进行相连,“重复出现”与链式结构互相配合就使范围查询变得十分简单,高效,举一个例子:进行范围查询id >= 4 and id <= 10,此时根据4找到对应的位置,在沿着链表往后遍历找到10就可以了,如果没有这个链式结构,就要反复对树进行回溯,那就会比较慢了;
- 针对B+树,查询的时间是很稳定的,因为B+树进行查询任何元素都是需要从根节点查询到叶子节点的,过程中经过的硬盘IO次数都是一样的(B树,有时候硬盘IO多,有时少),稳定比单纯的快更有用;
- 按照这个特点,存储数据只需要在叶子节点存储每个字段具体数据信息即可,其他非叶子节点只存储key即可,比如,我们创建了一个学生表(id,name,gender,classid.......),此时对id使用索引,因此非叶子节点只存储了id,由于id占用空间比较小,所以这些非叶子节点的数据可以缓存到内存,这样在查询的时候,只进行内存的比较,就大幅度减少了硬盘的IO次数了。
此处对B+树只是粗略的介绍,在后面文章中,我会再对B+树进行更详细的介绍。
二、事务
1.事务的概念
事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。 在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务。
对于数据库事务中有一个非常经典的场景:转账,例如有一天张三给李四转账500,这时数据库就需要修改张三的余额减少500,然后再修改李四的余额增加500,但是在其中修改张三余额之后数据库出现问题崩溃了,没有执行修改李四余额增加500的操作,等数据库好了之后就会发现,张三的余额少了,但是李四的余额并没有多,为了解决这种问题,所以引用了事务,这就是事务应用的一个经典场景。
2.事务的特性
(1)原子性
原子性,就是指通过事务把多个操作打包到一起,这也是事务最重要的特性,也是事务的初心。
(2)一致性
一致性,就相当于原子性的延伸,当数据库中间出现了问题,不会产生像上述转账场景中“钱凭空消失”这种不科学的情况,并且还可以通过约束,来避免数据出现一些非法的情况。
(3)持久性
持久性,就是事务的任何修改都是持久化存在的(写入硬盘),这样无论是重启程序,还是重启主机,所进行的修改都不会丢失(数据库本身就是为了持久化存储)。
(4)隔离性
隔离性,就是多个事务并发执行的时候,可能会带来一些问题,通过隔离性来对这里的问题进行权衡,这时就看你希望数据尽量准确还是希望速度尽量更快了。
3.有关事务典型问题
(1)脏读问题
当前有两个事务a和b:
事务a:修改了某个数据,但是事务还没有“提交”(提交是指告诉服务器当前指令执行完毕)
事务b:读取了同一个数据。
此时,事务b读到的数据很可能是一个脏的数据,因为事务a后续可能还要修改这个数据。
解决脏读问题,核心思路就是降低事务的并发程度,给写操作加锁(加锁,意味着释放锁之前,你是不能访问的),写的时候不能读,写完并且提交事务之后(释放锁),才能让别人读。
(2)不可重复读问题
不可重复读问题与脏读问题有点像,但不可重复读是在“写操作加锁”的前提下导致的问题,这里虽然写操作加锁了,但是可以分成多个事务,多次提交的方式来修改数据。
当前有事务a、事务b和事务c:
事务a:先修改某个数据(加锁),此时别的事务想读数据,得等事务a提交完。
事务b:事务a提交完,事务b开始读数据(事务b中可能会多次读取数据)。
事务c:进行修改上述数据。
此时,在事务c修改完数据,事务b还在读数据,就会导致事务b在一次事务中读到的数据结果不一样,就好比在买东西时,开始看还是30元,等再看时变成60元了,这样就会导致购物体验很不好。
解决不可重复读问题,就需要给“读操作加锁”,相当于在事务b读取数据时,别的事务不能对这个数据进行修改,这样就使并发程度降低了,数据的准确性提高了。
(3)幻读问题
有事务a、事务b和事务c三个事务:
事务a:先修改某个数据(加锁)。
事务b:等事务a提交完,开始读数据(加锁),此时不能修改数据。
事务c:新增一个其他数据。
此时,事务c新增了一个其他数据,导致事务b在进行多次读取数据时,两次读到“结果集”不一样(结果集就类似查询的时候查询的行数)。
解决幻读问题,可以使所有操作串行化,不再进行任何并发了,每个事务都是串行执行(执行完第一个,再执行第二个……)此时并发程度最低,同时数据的准确性最高。
4.隔离级别
在MySQL配置中,提供了“隔离级别”这样的选项,我们可以根据需要调整隔离级别,以适应不同的情况。通常事务之间影响越小,隔离程度就越高。
(1)read uncommitted
读未提交,这是并行程度最高的,隔离程度最低的,效率是最高的,数据是最不靠谱的。此时就可能出现:脏读、不可重复读、幻读这些问题。
(2)read committed
读已提交,相当于给写操作加锁,并行程度降低了,隔离程度提高了,效率会降低一些,数据会更靠谱一些。此时可能会出现:不可重复读与幻读这些问题。
(3)repeatable read
可重复读,相当于给读操作和写操作都加锁。并行程度降低了,隔离程度提高了,效率再降低一些,数据更加靠谱。此时可能出现:幻读这种问题。repeatable read是MySQL中默认的隔离级别。
(4)serializable
串行化,相当于让所有事务都串行执行。并发程度最低,隔离程度最高,效率最低,数据最靠谱。
5.事务的使用
有关事务的使用,在这我只简单的介绍一下有关事务使用的几个关键字:
start transaction; --执行事务之前,开启事务
commit; --告诉服务器,事务完毕
rollback; --告诉服务器,要进行回滚,把开始事务之后执行的SQL恢复回去
关于rollback操作,一般不会在控制台使用,以Java为例,会在Java代码中使用,Java代码开始事务,执行SQL,某个SQL抛出异常,在catch语句中捕获到异常时使用rollback。
·尾声
文章到此就要结束了,上述有关索引与事务的介绍是比较基础的,事实上,有关索引与事务,两个概念都有很多的内容,在本篇文章中就是先简单让大家知道索引与事务是什么,介绍了一些基础的概念,一些基础的使用还有一些需要注意的事项,后续文章还会对这两个重要概念进一步介绍,如果本篇文章对你有所帮助,希望能点赞收藏支持一下咯~~~~您的支持是我最大的动力,让我们在下一篇文章见吧~~