MySQL事务和索引

时间:2022-11-18 08:52:29

✏️作者:银河罐头
????系列专栏:MySQL

????“种一棵树最好的时间是十年前,其次是现在”

索引

概念

索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引,
并指定索引的类型,各类索引有各自的数据结构实现。

索引相当于书的目录,可以提高查的速度。但是索引也提高了增删改的开销,因为进行增删改会需要调整已经创建好的索引目录,降低增删改的速度。索引还提高了空间的开销。

增删改中包含查,总体来看查的频率高于增删改,所以索引对于提高数据库的性能有很大的帮助。

使用

学生表里没有创建索引但是自带一个索引

MySQL事务和索引

因为主键要保证非空且不重复,所以每次插入数据都要检查是否已经存在,有索引可以提高查找速度。

unique和foreign key也会自动创建索引

  • 创建索引

    MySQL事务和索引

    根据名字这一列来创建索引

    创建索引,最好是在创建表的时候就创建索引。如果在表已经有很多记录的时候再创建索引是危险操作(会消耗大量的磁盘IO,花很长时间,在这个时间段里数据库无法正常使用)。

    如果对性别或者大学生的年龄这样的列创建索引,这样无法提高查找速度,因为太多重复。

  • 查看索引

MySQL事务和索引

  • 删除索引

    MySQL事务和索引

    删除索引也可能消耗大量的磁盘IO

    SQL是通过数据库的执行引擎来执行的,涉及一些优化操作。执行引擎会自动评估哪种方案是成本最低速度最快的。

    可以使用explain关键字显示出查询过程中具体使用索引的情况。

索引在MySQL中的数据结构

哈希表查找元素时间复杂度是O(1),但是哈希表不适合做数据库的索引。原因是哈希表只能比较两个元素是否相等,不能进行’>‘、’<'这样的范围查询

二叉搜索树的时间复杂度是O(1),AVL/红黑树的时间复杂度是O(MySQL事务和索引)

(二叉意味着元素个数越多,树的高度越高,查询时元素的比较次数越多,数据库进行比较是要读硬盘的。)

  • N叉搜索树:每个节点上有多个值,同时有多个分叉,树的高度就降低了。

其中一种典型代表是B树

MySQL事务和索引

比较次数没有减少,一个节点上可能需要比较多次,但是读写硬盘的次数减少了,每个节点都保存在硬盘上。(读硬盘比读内存要慢几千倍)

对B树做进一步的改进,又引入了B+树

索引的数据结构就是B+树

MySQL事务和索引

1.B+树也是一个N叉搜索树,每个节点上可能包含N个key,N个key 划分出N个区间,最后一个key相当于最大值。

2.父元素的key会在子元素中以最大值形式重复出现。(这样一来叶子节点就包含了所有数据的全集)

3.会把叶子节点用类似链表的方式首尾相连

B+树的优点:

1.作为一个N叉搜索树,高度降低使得读硬盘IO次数减少(这一点同B树)

2.更适合做范围查询

3.所有的查询都要落在叶子节点上,无论查询哪个元素,查询的比较次数很均衡

4.由于所有的key都会在叶子结点上体现,所以非叶子节点上不用存表的真实记录(不必存数据行),只需要把所有数据行放在叶子结点上即可,非叶子结点只用存索引列的值(比如id)。

由于非叶子结点只存了索引列的值,没有存数据行,这样意味着叶子节点占用的空间大大降低,有可能放进内存中缓存,这样进一步降低了硬盘IO

  • 提高查询速度,本质上是降低硬盘IO次数

有的表不只是主键索引,还有别的非主键列也有索引(比如前面的把name作为索引)。

这种情况会构造另外一棵B+树,这个B+树非叶子节点存这个索引列里的Key(比如一些name)。到了叶子节点这一层,存的不是完整的数据行,而是存主键id。

使用主键列来查询,只要查一次B+树就可以。

使用非主键列的索引来查询,就要先查询索引列的B+树,再查一遍主键列的B+树。

“再查一遍"这个操作是"回表”。

当前B+树这个结构,只是针对MySQL的InnoDB(最主流使用的一种存储引擎)这个数据库引擎 里面典型使用的数据结构。不同的数据库,不同的引擎,里面存储数据的数据结构还可能存在差异。

数据库的存储引擎,其实就是实现了数据库如何在硬盘上组织数据。

MySQL事务和索引

事务

概念

事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。

事务的四大特性:原子性、一致性、持久性、隔离性

举例1:转账

1)给1的余额-100

2)给2的余额+100

举例2:下订单

1)商品库存-1

2)订单表+1

这些操作是要么全部成功,要么全部失败(执行中途出错的情况)。

  • 原子性:把所有操作打包成一个整体

执行中间出错了,就让一条都不执行,意思是恢复成执行之前的样子,看起来像是一条都没执行。

回滚(rollback):把执行过的操作逆向恢复回去。

数据库会把执行的每步操作都记录下来,如果某个操作出错就会把事务中前面的操作进行回滚,根据之前进行的操作进行逆操作。

这些操作有很大开销,不可能无限保存,最多是把正在执行的这个事务保存。

MySQL事务和索引

开启事务之后,中间这些sql不会被立刻执行,而是先攒着,等commit再一起执行。(原子性)

  • 一致性

事务执行前/后数据都是合法状态。

  • 持久性

硬盘断电数据不丢失,事务产生的修改都会写入硬盘。即使程序重启/主机重启/掉电,事务都可以正常工作,保证修改是持久生效的。

  • 隔离性

一个数据库服务器,同时执行多个事务的时候,事物之间的"相互影响程度"。

一个服务器可以同时给多个客户端提供服务,这多个客户端彼此之间是一个"并发执行"的关系

如果隔离性越高,就意味着事务之间的并发程度越低,执行效率越慢,数据准确性越高;

如果隔离性越低,就意味着事务之间的并发程度越高,执行效率越快,数据准确性越低。

mysql的隔离级别

  • “脏读”

事例:假设张三在写一份文件,李四在旁边看,此时张三的写操作和李四的读操作是2个事务,是完全并发的,没有任何限制。等李四走了张三把文件内容改了,那么李四读到的就是错误数据,这就是"脏读"。

解决"脏读"问题就要提高隔离性,降低并发性,具体来说就是给这里的写操作加锁。张三写文件时加锁,写文件过程中李四不能读,等张三写完了之后李四才可以看。整体上花的时间更多了,李四读到的数据准确性提高了。

  • 不可重复读

事例:有了"写加锁",等张三写完文件之后,李四再读文件,而在李四读文件过程中,张三又修改了文件内容,此时李四读文件读了一半发现文件内容自动变了。

在一个事物中,连续两次读到的数据不一致,这就是"不可重复读"

解决:给"读操作"也加锁,李四读文件的时候张三不得修改。

这样使得这两个事务的并发程度进一步降低,隔离性进一步提高,执行效率进一步降低,数据准确性进一步提高

  • 幻读

事例:李四读文件时,张三不能修改李四正在读的那份文件,但是张三去新增/删除另外的文件,导致李四发现他读的文件内容没变,但是他发现文件的数量变了。

在同一个事务中,两次读到的结果集不同。这就是"幻读"

解决:串行化,彻底舍弃并发。李四读文件时,张三什么都不能做。

MySQL提供了4个隔离级别

隔离级别 描述 脏读 不可重复读 幻读
read uncommitted 不做任何限制,事物之间可以随意并发执行。并发程度最高,隔离程度最低。
read committed 对写操作加锁,并发程度降低,隔离性提高
repeatable read (默认档位)对写和读都加锁,并发程度进一步降低,隔离性进一步提高。
serializable 严格串行化,并发程度最低,隔离性最高,执行速度最慢

通过mysql的配置文件来调整隔离级别