【数据库】——索引和事务


上一篇关于数据库存储引擎的概述文章中,我们就有接触到事务、索引、锁等相关概念。那么他们究竟是什么呢?下面就详细讲解一下吧~

一、索引

1、什么是索引

索引是一种特殊的文件(InnoDB数据表上的索引式表空间的一个组成部分),他们包含着对数据表里所有记录的引用指针。

通俗一点来说,索引就好比一本书前面的目录,能加快查询速度。在没有索引的情况下,数据库会遍历全部200万条数据后选择符合条件的,但是有了相应的索引之后,数据库会直接在索引中查找符合条件的选项、

2、索引的类型

(1)普通索引
是最基本的索引,他没有任何限制,MyIASM中默认的btree类型的索引。

  • 直接创建索引
    在这里插入图片描述

  • 修改表结构的方式添加索引
    在这里插入图片描述

  • 创建表的时候同时创建索引
    在这里插入图片描述

  • 删除索引
    在这里插入图片描述
    (2)唯一索引
    与普通索引类似,不同的是,索引列的值必须唯一,但是允许有空值(注意和主键不同)。
    创建方法和普通索引类似,区别在于前面加一个unique
    在这里插入图片描述
    (3)全文索引
    全文索引仅用于MyISAM表中。可以从char、varchar或text列中作为create table语句的一部分被创建,或是随后使用alter table或create index被添加。

注意!!!对于较大的数据集,将你的资料输入一个没有fulltext索引的表中,然后创建索引,其速度比把资料输入现有fulltext索引的速度更为快。
在这里插入图片描述
(4)单列索引、多列索引
多个单列索引与单个多列索引的查询效果不同。因为执行查询时,MySQL只能使用一个索引,会从多个索引中选择一个限制最为严格的索引。

3、MySQL索引的注意事项和优化方法

索引大大提高了查询速度的同时会降低更新表的速度。因为
在insert,uodata和delete时不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。

(1)索引不会包含有NULL值的列
复合索引也同样,只要有一列含有NULL值,那么这一列对于此符合索引就是无效的。

(2)使用短索引
列如,有一个char(255)的列,如果钱10个或20个字符内,多数值是唯一的,那就对串列进行索引,如果可以的话应该指定一个前缀长度。
短索引不仅可以提高查询速度而且可以节省磁盘空间和i/o操作

(3)不要在列是哪个进行运算
例如:select * from users where year(adddata)<2007.这个语句将在每个行上进行运算,这将导致索引失效而进行全表扫描。因此我们改成:select * from users where adddata<‘2007-01-01’

(4)哪种情况下应该建立索引
经常需要搜索的列上,可以加快搜索的速度;
作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

(5)哪种情况下不应该建立索引
第一,对于那些在查询中很少使用或者参考的列不应该创建索引
第二,对于那些只有很少数据值的列也不应该增加索引。
第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。

二、事务

事务是由单独单元的一个或多个SQL语句组成,在这个单元中,每个MySQL语句是相互依赖的。

1、事务的ACID

A:原子性:事务里面的操作,要么全部执行成功,要么全部失败回滚,不可以只执行其中的一部分。

**C:一致性:**一个事务的执行不应该破坏数据库的完整性约束

I:隔离性:事物之间的行为不应该互相影响

D:持久性:事务提交之后,需要将提交的事务持久化到磁盘。

2、事务不隔离产生的影响

1)丢失更新
两个事务同时更新一行数据,但是第二个事务却中途失败退出,导致两个修改的数据都失效

(2)脏读
一个事务正在访问一个数据并且对其进行了修改,但是这种修改还没有被提交到数据库,另外一个事务也访问这个数据,然后使用了这个数据。

例如:张三的工资5000,A将其修改为8000.此时A发生异常,张三的工资又回滚成了5000.但是B去读的8000的数据就为脏数据。
在这里插入图片描述
解决办法:事务执行过程中获取不到其他事务执行过程的结果。

(3)不可重复读
在一个事务内,多次读同一数据。在这个事务还没有结束时,宁一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
是基于解决了脏读后的情况

产生原因:事务在执行过程中读取了其他事务不同阶段的结果
处理方式:事务在其他事物执行过程中开启,其他事务相对于该事务透明。如下图所示,B事务在A事务执行过程中开启,A事务相对于B事务是透明的,B事务执行看见A1过程的数据。
在这里插入图片描述

(4)丢失更新
在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。
  与此同时,
  事务B把张三的工资改为8000,并提交了事务。
  随后,
  在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。

(5)幻读
产生原因:事务执行过程中获取到其他事务不同阶段的结果
不可重复读是因为修改操作导致,幻读是因为插入和删除导致
在这里插入图片描述
处理方式:间隙锁
  
MySQL中支持事务的存储引擎有innoDB和NDB.。事务的隔离性是通过锁实现。

3、隔离级别

(1)在以下相应隔离级别之下会出现如下问题
在这里插入图片描述
但是第四隔离级别是以串行的方式,效率会非常低。
可用如下的方式来查询数据库的隔离级别
在这里插入图片描述
从该命令可以看出,mysql默认的隔离级别为不可重复读

修改隔离级别
在这里插入图片描述
(2)当前隔离级别和全局隔离级别
全局隔离级别是服务器的隔离级别而当前隔离级别则是客户端的隔离级别。当开启一个客户端的时候,服务器为其拷贝一个隔离级别的副本。
在这里插入图片描述

4、如何保证ACD

采用加锁的方式不能保证原子性,因为锁还是一种软件机制,一旦发生断电事务不能保存。所以采用日志系统,详情如下:

  • redo log(事务将要执行的每一个操作)
    “日志先行策略”——事务开启时,事务中的操作都会先写入存储引擎的日志缓冲中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘持久化。
    此时如果数据库崩溃或者宕机,那么系统重启进行恢复时,就可以根据redo log中记录的日志,把数据库恢复到崩溃前的一个状态。
    如:
    记录1:<trx1, insert…>
    记录2:<trx2, delete…>
    记录3:<trx3, update…>
    记录4:<trx1, update…>
    记录5:<trx3, insert…>

  • undo log
    主要是事务的回滚服务,里面记录了数据在每个操作前的状态。下面是undo+redo事务的简化过程:
    假设有2个数值,分别为A和B,值为1,2

  1. start transaction;
  2. 记录 A=1 到undo log;
  3. update A = 3;
  4. 记录 A=3 到redo log;
  5. 记录 B=2 到undo log;
  6. update B = 4;
  7. 记录B = 4 到redo log;
  8. 将redo log刷新到磁盘
  9. commit
    在1-8的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。如果在8-9之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时redo log已经持久化。若在9之后系统宕机,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复之后,可以根据redo log把数据刷回磁盘。

综上所述:redo log其实保障的是事务的持久性和一致性,而undo log则保障了事务的原子性。

发布了62 篇原创文章 · 获赞 7 · 访问量 2556

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/104818754