数据库的索引和事务

        1.  索引是一种特殊的文件,包含着对数据表中所有记录的引用指针。

  • 索引的作用类似于书籍中的目录,可以帮助我们快速查询到需要查询的记录,对于提高数据库的性能有很大的帮助。
  • 对数据创建或删除索引是一件比较低效的事情,尤其是存储了大量数据的时候,所以索引一般在数据库建表的时候就会创建好。如果是操作线上数据库,并且这个数据库存储了大量数据那么一定不能冒然给这个数据库创建或删除索引,否则可能导致数据库挂掉,最好是在建表之前就规划好是否要使用索引,避免在数据量大了之后再去创建或删除索引。
  • 索引对于检索速度的提升在一定程度上牺牲了空间,并且拖慢了对数据的增删改,但在实际工作中,我们对数据的操作一般是“多读少写”,所以提高查询速度是非常有必要的,即使这会在一定程度上拖慢增删改。
  • 关于实现索引所使用的的数据结构。顺序表可以通过其自带索引来进行快速查找,但顺序表的增删改需要对顺序表内的数据进行整体的移动,非常的麻烦。链表虽然在增删改上稍微方便一些,但创建索引的目的是加快查找,而链表的查找时间复杂度为O(N)。哈希表的查找和修改都是O(1)但只能对相等进行比较,不能实现大于、小于的范围查找。二叉搜索树看起来很符合条件,但在数据量较大的时候,二叉搜索树的高度会变得非常大,高度高了比较次数就多,搜索就慢,那么只要解决二叉搜索树高度的问题,即将二叉搜索树变为多叉搜索树,基本就可以确定索引的数据结构了,就是我们说的B树。
  • B树是在每个节点储存N个Key值,通过这些Key值划分出N + 1个区间,每一个区间就是一个子树,子树也同理,存储的Key值再分区间,直到最底的叶子节点。通过这些区间就能快速完成指定范围内的快速查找。但是B树还不是最后实现索引的数据结构,真正实现索引的是在B树的基础上B+树。
    B+树每个节点中存储的N个值直接分成N个区间,同时会将自身存储的值再子节点中体现,最后再将存储了所有值的叶子节点以链表的形式连接起来。因为所有的值都在叶子节点中存好了,所以非叶子节点就只需要存储一些代表地址的Key值,这些Key的大小都非常小,甚至可以直接存在内存中,这样就极大程度减少了IO次数,提高了搜索的速度。
  • 虽然实现数据库索引的基本数据结构就是多叉搜索树,但是数据库也有很多不同的,不同的数据库底层实现索引所用的搜索树其实现方法也都有所不同,B+树就是其中最常用的一种。

 

  •  在MySQL中,我们通过一下的SQL语句来操作索引。
    show index from ; //查看索引,from 后面加需要查询的表格名字。
    create index on ; //创建索引, create index 索引名 on 表名() 括号内写入用做索引的字段名。
    drop index on ; //删除索引,drop index 索引名 on 表名。

        2.事务是将几条SQL语句包在一起执行,有4个基本的特性。

  • 原子性:这是事务的核心特性,它描述的是事务中的SQL语句要么都执行,要么都不执行。例如我们平时在进行转账时,数据库内是先进行扣款操作,再进行收款操作,如果扣款执行失败了,就不会给收款方增加余额。事务在保证一致性时,并不能在执行失败前就预判到这次执行会失败,所以事务实际上是先试执行,在执行失败后,就进行回滚,或是对数据进行逆操作来还原数据,或是在执行之前先备份好,执行失败就直接通过备份还原数据。
  • 持久性:事务执行成功之后,对数据造成的影响是持久的,修改后的数据是直接存入到硬盘中的。
  • 一致性:事务执行时,会保证执行成功之后与执行成功和之前的数据存在一致性,例如转账时,对转账方的数据操作是减500,那么收账方的数据就一定是加500。
  • 隔离性:这也是事务中非常重要的一个特性,它描述的是事务在并发执行时会出现的一些情况。
    在多个事务并发执行时,由于同时有多个事务对数据进行读写操作,那就有可能导致读取的数据出现问题。
    (1)脏读问题:举个简单的例子来说明这个问题。当我在写代码时,我定义了一个变量 i = 10,如果在我写的时候有人读取了这个变量的值,并且拿去使用了,而在他读取之后,我又修改了这个值,那就会导致他读取到的值出现问题。要解决脏读问题,我们可以通过约定,在我代码还没写完时,不能对我的代码进行读取,相当于加入了一个“写锁”,保证写代码时的安全性。
    (2)不可重复读问题:如果只是单纯的加入“写锁”,保证在写完之前不能读取,那如果在第一版的代码写完之后就立刻去进行读取,在读取的同时,我又对代码进行修改,那在读完的时候就又会发现代码又不一样了,这就会导致不可重复读问题。要解决这个问题,我们又进行约定,保证在读取代码完成之前,都不对代码进行修改,相当于一个“读锁”。
    (3)幻读问题:虽然我们已经给读写操作都加了锁,但是这个锁并不是完全的锁死,具体要看锁的力度,就像疫情时期,每个城市对疫情的管控力度是不同的。如果我们在Java.A文件编写完成之后,去读取Java.A,按照约定,这时我不能修改Java.A的代码,但我可以去Java.B文件。这样就会导致,读取前只有一个文件记录,读取之后就发现多了一个记录。要解决幻读问题,就只能是让事务串行运行,即,在写的时候就不读取,读取时就不写,这样就一定会拖慢运行的速度。
  • 这时我们发现了,隔离性和并发性是不能兼得的,隔离性高,并发性就会降低,就是说在保证安全的情况下,运行速度会相对下降,这就需要根据具体情况去取舍了,在实际工作中灵活的调整事务的隔离级别就可以有效的提高我们的工作效率。
  • 在MySQL中提供了四种不同的事务隔离级别。
    (1)read uncommitted : 允许读取未提交的数据,并发程度高,隔离程度低,会引发脏读、不可重复读、幻读问题。
    (2)read committed : 只允许读取提交之后的数据,相当于加入“写锁”,并发程度稍降低,隔离程度提高,会引发不可重复读、幻读问题。
    (3)repeatable read : 相当于读写都加锁,并发程度进一步降低,隔离程度降低,会引发幻读问题。
    (4)serializable : 串行执行,一个事务完全执行完之后才能执行下一个事务,并发程度最低,隔离程度最高,结局了脏读、不可重复读、和幻读问题,但执行速度最慢。
  • 在MySQL中事务的SQL语句结构大概是这样的:
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值