由于数据库中的数据十分繁杂,因此我们在增删查改数据的时候需要找到数据的具体位置,为了更加快捷的找到这个数据,我们采取了以空间换时间的做法。为表中添加索引。
所谓索引,就是类似于图书的目录一样,可以快速的检索目标
当我们对数据库创建一系列的约束时(详见上一篇blog),我们的数据库就会自动的创建索引
create index 索引名 on 表名(列明);
drop index 索引名 from 表名;
show index from 表名;
需要注意的是,由于索引是为了我们更方便查找数据,因此在需要查询频率高的列,我们可以创建索引,而数据的变动也影响索引的排列,因此我们在增添,删除,修改频率高的列最好不使用索引。
前面的blog介绍了不少的数据结构,顺序表,链表,二叉树等等,我们可以思考一下索引用的是哪种数据结构
答案是:哪种都不是,索引用的数据结构是B+树,之所以叫B+树,是因为还有B树,B树和二叉树搜索树类似,只不过是n叉搜索树。
而B+树,其每一个非叶子结点存储的都是数据的大致信息,而叶子结点存储了所有的信息。
例如我们要存储学生信息,张三,19,高中,我们就把19存储在非叶子结点中,便于寻找也减少了内存的负担
事务是指在完成任务的一系列操作单元要么全部成功,要么全部失败。
通俗来讲,就是由于数据的庞大性,某些操作可能会导致数据库崩溃,而导致某些应有的数据的变更并没有生效或者生效多次,因此我们需要事务来避免因此出现数据的错误
开始事务
start transaction;
然后我们就可以编写一系列SQL语句,直到我们的任务结束
回滚
即全部失败,将数据回撤到上一个存档
rollback;
提交
即全部成功,结束事务的使用
commit;
需要注意的是,之所以需要事务来实现类似“撤回”的功能,是因为我们的数据量很大,在存档数据时十分麻烦,十分浪费资源,因此需要我们手动选择是否开启事务。
由于我们的数据库操作可能是多线程操作,因此涉及到以下几种问题
当一个事物正在修改数据,而另一个事物读取了修改前的数据并使用了这些数据
例如当两个同事合力完成同一个任务,a完成了一部分代码并上传到github,b通过github获取到了这些代码,并沿着这段代码继续编程,但是a发现这个代码有问题,修改了代码,这时b所读的数据就是脏数据
我们的解决方法就是把写操作加锁,当我们一个事物写操作时另一个事物无法读取该数据
当一个数据在读数据时,另一个事物将数据修改了,导致数据读取的内容不一致
例如当两个同事合力完成同一个任务,b通过github获取到了a的代码,但是读着读着a把代码改了,导致b读的代码不一样了
我们的解决方法是对读操作也加锁,当我们一个事物读操作时另一个事物无法修改这些数据
和不可重复读类似,由于另一个事物的干涉,导致事物在读取数据时发现数据总量和第一次读取不一致。而不可重复读是两次读取事物的数据内容不同
例如当两个同事合力完成同一个任务,虽然规定了b在阅读a的代码时,a不能更改这个代码,但是a可以去新建另一份代码,也就是当b再阅读代码时,发现有两个文件了
解决方法就是“串行化”,也就是当b在进行读操作时,另一个事物什么事也不能做
由于我们把事物的处理变得“原子化”——也就是说在一个事物操作时,另一个事物无法对数据进行处理,导致了我们的效率有所下降。这个过程就是拿效率换取数据准确度的过程。
因此,对于不同的场景,我们对数据的效率和准确度的要求不同,MySQL提供了四种隔离级别以应对不同的需求
由上到下隔离级别变高,效率下降,数据的准确度提升
隔离级别 | 效果 | 问题 |
---|---|---|
read uncommitted | 允许读未提交的内容 | 出现脏读,不可重复读,幻读 |
read committed | 不允许读未提交的内容 | 出现不可重复读,幻读 |
reaptable read | 读和写都进行加锁 | 出现幻读问题 |
serializable | 串行化 | 效率低下 |
我们的MySQL默认是repeatable read |