MySql-索引&事务

在面试中,对于mysql相关的面试题常看的两部分也是我们学习时需要重点了解的内容:索引与事务。

目录

索引

B树

B+树结构

B+树创建

事务

重点:事务的基本特性

一、原子性

二、一致性

三、持久性

四、隔离性


索引

索引的核心内容:底层的数据结构。

索引引入了一些额外的数据结构来加快查询的速度,默认条件下进行条件查询就是遍历表一条一条数据代入条件查询,引入索引就是要通过其他数据结构加快查询的速度,减少遍历表的可能。

哪些数据结构能加快查询的速度?

顺序表->随机存取,链表-》中间位置删改,栈/队列-》特殊位置操作,二叉搜索树(红黑树)

但是红黑树和哈希表这两个数据结构都不适合用在数据库,原因:

1、哈希表只能查询key相等的情况,大于和小于的范围查询是做不了的;通过hash函数的映射,原来key之间的大小关系不能反应到计算出来的hash值的大小关系,也无法决定下标的关系。

2、对于红黑树呢是可以进行范围查询的,但是对于在红黑树里进行中序遍历找后继节点的方式也未必是高效的,很有可能需要往父亲节点进行一系列回溯才能找到后继

对于原因一可以用过线索化的方式解决,但是要付出更多的存储空间

原因二:红黑树是二叉搜索树,当元素非常多就会使树非常高,树的高度越高进行查询的效率就越低,高度每增加一层就要增加一次比较的次数,而数据库的数据/索引都是保存在硬盘上的,每比较一次就要进行一次硬盘IO操作,因此红黑树不适合大规模在硬盘上管理数据的情景。

B树

结合 上述,于是就引入B树,本质上是N叉搜索树,每个节点上可以存储多个元素,延申出多个子树,同样数量的数据,需要的节点少了,对应树的高度也就大大降低了,大概长这样:

此时拿着要查询的key在某个节点要进行比较时,确实需要更多的比较次数,但这里的比较其实是很高效的,原因:

(1)每个节点上key都是有序排列,比较时可以使用二分查找

(2)B树会控制每个节点上的key值不会太多,如果还要添加新的数据,那么就会分裂更多的子树出来。

(3)多个数据都是存储在一块连续的空间,进行比较时一次硬盘IO操作就可以读出整个节点,可以直接完成上述操作,也就是多次比较仅需要一次IO操作

B+树结构

B+树是B树的升级版,还有称为B-树的,也是B树。首先我们看例图:

需要注意B+树结构上的这些特点:

(1)根节点上的最右值30可以认为是这棵树的最大值

(2)每个根节点的子树的值最大值为父节点的值

(3)非叶子节点的值都会在叶子节点出现

针对索引列进行的查询,是从树的根节点一层一层进行查询。针对非索引列查询就是从最底下层的叶子结点遍历链表就行了。

按照上述规则排列数据,此时叶子结点这一层包含整个数据集合的全集。另外B+树会把叶子节点通过链表这样的链式结构串起来,此时就通过上述链式结构非常方便的遍历整个表的所有数据,同时也非常方便进行范围查询。

B+树相对于B树的优势:

(1)非常方便进行遍历和范围查询。

(2)当前任何一次查询操作最终都会落到叶子节点,也就是说查询任何数据经历的硬盘IO次数都是一样的,查询操作消耗的时间是稳定的。

稳定是很重要的,有些时候查询数据可以直接在B树的非叶子节点查询到,查询操作消耗的时间确实是更少了但是有的操作慢有的操作快这件事是非常不稳定的。

(3)由于叶子节点存储了全部的数据,相对应非叶子节点都是重复的数据,所以在非叶子节点可以只保存一个key值,表的每一行的数据都只关联到叶子节点上;这样创建后非叶子节点占用的空间比较小,此时可以把非叶子节点保存到内存中的缓存中,大大提高了查询的效率。

B+树创建

咱们看到的表格是逻辑上的结构,实际底层的结构就是B+树的结构,B+树按照主键的索引的这个B+树的叶子节点来保存每一行数据;如果你的表创建主键了,就会按照主键的索引的B+树创建所有行,如果你没有创建主键,mysql就会生成一个隐藏的主键,按照隐藏主键创建的树来组织数据。查询时如果查询的列不是索引列,那么就会一行一行的全盘遍历。

总结(这里理解起来可能会有点困难)针对哪个列创建索引就是针对哪个列创建B树,主键索引的B+树叶子节点带有数据行,其他列索引创建的树叶子节点存储主键的id,针对非主键索引查询最终会得到一个主键的id,再拿着这个id去主键索引树查询,这个过程称为回表。

事务

日常开发中很多操作不能只通过一条sql完成,往往需要多条sql配合完成,当执行多个sql操作时,如果中间出现了特殊的情况可能会使前面的sql成功后面的sql失败

比如说转账的情景:

此时我们的逻辑是1给2转账,1的钱减少500然后2的钱增加500,可能就会出现第一条语句执行成功,1的钱减少500,中间出现错误导致第二条执行失败,那1就白白的丢了五百块,此时转账失败。

这个时候就需要事务来保证上述操作是可靠完整的。

事务就是将多个操作打包成一个整体,能够保证这个整体要么都执行,要么都不执行,不会出现部分执行成功部分执行失败的可能,解决了由“中间状态”引起的问题。

这里的都不执行不代表真的一条都没执行,事务中的操作是一条一条执行的,当执行到某一个条出现了问题,数据库可以把前面sql操作产生的影响恢复回去,看起来好像一条sql都没有执行的样子,这样操作称为——回滚

能完成这样的操作全靠了日志。为了实现回滚机制,数据库会在执行事务的时候记录日志,当事务都执行完毕,中间没有错误,这些记录的内容就可以不要了,如果执行事务的过程中出现了问题,mysql就可以通过日志中记录的内容来恢复操作。

只要数据库处于正常工作的状态,就能保证之前事务进行的操作能够正确回滚。

重点:事务的基本特性

一、原子性

有回滚操作,能够进行还原。

二、一致性

执行事务之前和执行事务之后数据是一致的,不会出现对不上的情况。

当触发回滚后,回滚之后的数据是要正确的,如果没触发回滚,也要保证操作产生的结果是正确的。

三、持久性

持久性->数据存在硬盘上,此处的持久性是程序重启/主机重启后数据依然存在。如果存储在内存就不是持久的。

执行事务对数据库进行的修改产生的影响,会在硬盘上永久保存,程序重启后依然存在。

四、隔离性

描述的是数据库并发执行事务时产生的情况。

不能确定客户端什么时候提交事务,可能多个客户端在同一时间提交事务,甚至可能要操作同一个表,而并发执行程序会引发一些问题:

(1)脏读问题假设数据库中有事务A与事务B,事务A在对数据进行一些操作后,还没向数据库提交时事务B就读取了修改的数据,导致后来如果A再对数据进行一些操作后,A提交的数据与B读到的数据是不同的,也就是此时B读到的数据是错误的。

如果约定:A提交数据之前B不可以对这个数据进行读写操作就可以解决脏读问题。也就是针对写操作加锁,引入加锁操作后,在A执行的过程中B就不可以在对数据进行操作了,要等待。

这就相当于降低了并发能力,降低了数据库服务器的处理效率,提高了隔离性,提高了数据的准确率。

写入加锁操作,相当于做出了取舍,用一部分效率换来了准确率并发执行的过程中,事务间的影响越小,隔离性越高;反之事务间的影响越大,隔离性越差。

(2)不可重复读问题假设数据库中存在三个事务ABC,事务A在对表进行修改操作后事务B开始对数据进行读操作,事务B中包括多个读操作,此时有一个事务C又针对数据进行了修改,就会可能导致B里面不同的读操作读出来的数据可能会不一样。

刚才是针对写操作进行加锁,A写的时候别人不能读,所以这个问题的解决也就是要针对读操作加锁,A读的时候别人不能进行写操作。

此时,并发能力进一步降低,数据库的执行效率也降低,隔离性增强,数据准确性提高。

(3)幻读问题事务A先对数据进行了修改操作,事务B在读数据时事务C没有修改B读的数据,但是给对应的表进行了新增/删除操作,导致B读到的数据集不同,此时已有的数据内容是一致的,但是数据的条数增加/减少。

解决幻读问题的方式——串行化。让事务完全严格的按照一个接一个的方式执行,此时完全没有并发了,数据库服务器的效率是最低的,隔离性是最高的,准确性也是最好的。

总结(1)脏读->写加锁 (2)重复读->读加锁 (3)幻读 ->串行化

解决上述问题的过程中,要想获得更高的隔离性就要牺牲一部分效率。

mysql中给用户提供了四个隔离级别,可以在mysql配置文件中设置:

(1)read uncommitted:允许读取其他事务未提交的数据->脏读+重复读+幻读

(2)read committer:只允许读取其他事务提交后的数据->重复读+幻读

(3)repeatable read:针对读和写操作进行加锁->幻读

(4)serializable:所有事务都是串行执行

道阻且长,行则将至

感谢观看

  • 32
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值