目录
索引
作用
查看索引
创建索引
删除索引
索引背后的数据结构
B树
B+树
事务
事务的本质
事务的特性
并发执行事务产生的问题
脏读问题
不可重复读
幻读
MySQL中隔离级别
read uncommitted
readcommitted
repeatable read
serializable
索引
索引的本质就是为了加快数据库的查询速度。但是有利就有弊,同时也付出了一定的代价:
- 空间代价来保存索引
- 索引可能会拖慢增加、修改、删除的效率
但是总体来说,利大于弊。
作用
- 数据库中的表,数据,索引之间的关系就像是书架上的书、书里面内容、和书的目录之间的关系。
- 索引的作用就是类似于书的目录,用于快速的定位,检索数据。
- 索引对提高数据库性能有很大帮助。
查看索引
创建索引
把表中的内容根据username创建了一个目录。
删除索引
索引背后的数据结构
根据特定的数据结构重新组织数据,在进行查询时,速度加快。
B+树:索引关键的数据结构。为数据库的索引量身制作的数据结构。
B树
我们先认识B树
B树可以认为是一个N叉搜索树。
B树由于是一个N叉搜索树,所以当节点上的子树多了之后,节点保存的key也就多了,这就意味着在同样key的个数前提下,B树的高度要比二叉搜索树低很多。
当树的高度越高时,进行查询比较的时候,访问磁盘的次数就越多。
B+树
在B树的基础之后做了修改。同时也是N叉搜索树。
整个树的所有数据都是在叶子节点上存储,而非叶子节点中的key最终都会出现在叶子节点上。
B+树的特点
- 一个节点,可以存储N个key,这N个key划分了N个区间(而不是N+1个区间)。
- 每个节点中key的值,都会在叶子节点存在,同时该key是子节点的最大值。
- B+树的叶子节点,是完整的数据集合,只在叶子节点这里存储数据的每一行的数据,而非叶子节点,只存储key值本身即可。
B+树的优势
- 当前一个节点上存储了更多的key,最终树的高度是相对更低的,查询的时候减少了IO的访问次数。
- 所有查询的节点最终都会在叶子节点上(查询任何一个数据,经过的IO访问次数是一样的)
- B+树的所有叶子节点构成一个链表,此时就更加方便进行范围查询
- 由于数据都存储在叶子结点上,非叶子节点只存储key值,导致非叶子节点占用空间时比较小的。
上述的B+树就是MySQL组织数据的方式。
也就是说当你看到一张数据库二维表时,实际上这个表不一定就是按照表格这样的数据形式来存储数据的,数据的组织结构也不在硬盘,也是很有可能就是按照上述的B+树来存储的。
具体是那种结构,取决于你表里面有没有索引,以及数据库使用了那种存储引擎。
上述B+树结构,就是默认按照ID为索引展开的。
事务
事务的本质
我们先来看看下面这样的情况:
比如转账操作:
账户表:account (id balance)
用户1要给用户2转账500块钱,那么在数据库中肯定是要把用户一的余额-500,把用户2的余额+500,如下SQL:
update account set balance = balance-500 where id = 1;
update account set balance = balance+500 where id = 2;
假如在数据库执行过程中,执行完成第一条语句之后,数据库宕机了,此时用户1的余额已经被扣除了,但是用户2的余额却没有到账。
事务就是为了解决上述问题。
事务的本质就是把多个SQL语句打包成一个整体,这个整体要么全部执行成功,要么全部执行失败。而不会出现上面这种执行一半的情况。事务保证原子性
如果采用事务出现了上述的这种情况,当第一条语句执行完成之后,数据库宕机了,当下次数据库重新启动的时候,就会把上次修改一半的数据进行恢复还原。
事务的特性
- 原子性(最核心的特性)。
- 一致性 事务在执行前和执行后,保证数据一定是有效的。
- 持久性 事务修改的内容是写在硬盘上的,持久存在的。
- 隔离性 这里的隔离性是为了解决并发执行事务的问题。
并发执行事务产生的问题
脏读问题
一个事务A在对数据进行修改的过程中,还没有提交之前,此时另一个事务B,也对同一个数据进行读取,此时B的操作就成为脏读。读到数据也是脏数据。(无效数据)。
解决方案
给写操作进行加锁,当给写操作进行加锁之后,在修改数据的时候就不能同时进行读取数据了,这就意味着写操作和读操作不能同时进行了,不能并发执行了。
这个给写操作进行加锁,将降低了并发的效率,但同时提高了隔离性。提高了数据的准确性。
不可重复读
事务1已经提交了数据,事务2开始读数据,在读取的过程中,事务3又提交了新数据。
这就意味着同一个事务2,对此读取数据,读取出来的数据是不一致的,(预期是一个事务中,多次读取结果都是一样的)。这就叫不可重复读。
解决方案
通过给读操作进行加锁,这就意味着在读数据库的时候,其他事务不能进行修改数据,这就保证了多次读取数据的一致性。但是同时也是降低了并发的效率。进一步提高了事务的隔离性,数据的准确性又提高了。
幻读
当前我们约定给读操作和写操作进行加锁,解决了不可重复读和脏读问题。
在给读加锁和写加锁的前提下,一个事务多次读取数据,发现数据值是一样,但是数据的结果集不一样。这就产生了幻读问题。
解决方案
数据库使用串行化的方式来解决幻读问题,具体就是彻底的放弃并发处理事务,采取串行方式来一个接着一个的处理事务,这样做,并发程度是最低的,同时效率也是最低的,但是隔离性却是最高的,数据的准确性也是最好的。
对于上述的问题,MySQL提供了4中隔离级别,就对应上述的几个情况。
MySQL中隔离级别
read uncommitted
没有任何的锁的限制,并发程度是最高的,效率也是最高的,但是隔离性却是最低的,数据的准确性是最低的。
readcommitted
给写加锁了,并发程度降低 隔离行提高了
repeatable read
给写和读都进行了加锁,并发程度又降低了,隔离性又提高了
serializable
彻底的串行化执行,并发程度最低,隔离性最高。
上述的4种隔离级别,但是MySQL内置的机制,可以通过修改MySQL的配置文件进行设置当前工作在那种状态下。