索引的特点
1)加快查询的速度
2)索引自身是一种数据结构,也要占用存储空间
3)当我们需要进行增删改的时候,也要对索引进行更新(也需要额外的空间开销)
sql操作
查看索引
show index from 表名;
查看某个表是否有索引,以及有几个索引
⚠在没有约束的情况下,数据表的索引是无法显示出来的
MySQL的unique,primary key和foreign key都可以自动生成索引
一个表的索引可以有多个,每个索引都是根据某个具体的列来展开的
创建索引
create index 索引名 on 表名(列名);
这个操作要慎用,如果表本身就有很多数据,此时创建索引操作会触发大量的IO
删除索引
drop index 索引名 on 表名;
索引底层的数据结构
采用B+树作为数据结构,前身B树,也叫B-树
B树是一个N叉搜索树,在二叉搜索树上进行拓展,要求这里是有序的
一个节点上可能包含N个值,N个值划分出N+1个区间
同样的高度的树,能表示的元素比二叉搜索树就多很多了
当采用B树进行查询时,总的比较次数增加了,但是同一个结点的这些key都是一次硬盘IO就都出来了,也就相当于内存1万多次的比较了
B+树是在B树上进行了改进
B+树的特点
1. 同样是N叉搜索树,每个结点包含多个key,N个key划分出N个区间
2. 每个结点的N个key中,会存在一个最大值
3. 每个结点的key,都会在子树中重复出现
(重复出现的好处:所有的数据都包含在叶结点这一层中)
4. 把叶结点站之间采用链式结构进行相连
1)此时进行范围查询,id>=4 and <= 10
先根据4找到对应的位置,沿着链表往后遍历到10就找到了
如果没有这个链式结构,就可能需要反复的对树进行回溯,就会很麻烦
2)针对B+树的查询时间是稳定的
查询任何一个元素,都是需要从根节点查询到子节点的
过程中经过的硬盘IO次数是一样的
3)只需要在叶结点存储数据,其他非叶节点存储key就行(这个key占用的空间很小)
数据库的事务
很多时候进行多个sql的操作,我们是希望将它们打包在一起的
第一个解决办法:不让数据库挂
但是数据库真挂了,我们也要有一个应对措施,采用事务
事务可以保证上面两个sql语句要么都执行成功,要么都不执行
(都不执行其实是有执行的,只是数据库恢复的时候,把数据都还原回去了,这叫回滚)
那数据库咋知道之前的数据是多少?
数据库对于事务有特殊的机制(undo log + redo log),通过日志打印,写道文件里
数据库中间挂了,但是日志已经记录下来了,数据库重启之后会读取之前的日志,对于在执行一半的事务会进行操作回滚
事务的核心特性
1.原子性。通过事务将多个操作打包在一起(事务最重要特性)
2.一致性。原子性的延申,当数据库中间出问题了,不会出现上述钱凭空消失的情况
另一方面,通过约束避免数据出现一些非法情况
3.持久性。事务任何的修改都是持久化存在(写入硬盘的),无论是重启程序,还是重启主机,修改都不会消失
4.隔离性。多个事务并发执行的时候会带来一些问题。通过隔离性来对问题进行权衡,看希望数据准确还是希望速度尽量快
并发:一个服务器会涉及多个客户端。如果多个客户端同时给数据库发起事务请求,就叫做并发执行事务
如果多个事务是修改不同的表,问题不大;修改相同的表会产生一些bug
典型bug1:脏读问题
当前两个事务1,2,其中事务1修改了某些数据但还未提交
事务2也读取了同一个数据,此时事务2读到的数据可能是一个脏的数据,因为事务1后续可能还要修改这个数据
解决脏读问题,核心思路是降低事务并发程度。
给写操作加锁(意味着在释放锁之前你是不可访问的)
写的时候不能读,写完提交(释放锁)后才可读
典型bug2:不可重读性
这个是写加锁的前提下导致的问题。虽然写加锁了,但是可以分成多个事务,多次提交的方式来修改数据。
有事务1,2。其中事务1先修改数据(写加锁),此时事务2想读数据,就需要等事务1提交完
等到事务1终于提交了之后,事务2开始读数据
又多了一个事务3,事务3又修改了上述的数据。导致事务2在读的过程中,两次读到的结果不同
也就是事务2在读的同时事务3又在写
所以解决这个问题很简单,给读加个锁就行了,相当于加个约定,读的时候不能写
典型bug3:幻读
有事务1,2。事务1修改数据,提交;事务2开始读数据
此时事务3新增了一个其他的数据,此时事务2就可能出现两次读取的结果集不同
解决幻读问题,用串行化,不进行任何并发了,每个事务是进行串行进行的
执行完第一个,再执行第二个,再执行第三个
MySQL配置中,提供了隔离级别的选项,程序员可以根据需要调整隔离级别,适应不同的情况
1)read uncommited 读未提交,并行程度最高,隔离程度最低,效率最高,数据最不靠谱,可能出现上面的三个bug
2)read commited 读已提交,相当于给写操作加锁,并行程度降低,隔离程度提高,效率降低,数据更靠谱
3)repeatable read 可重复读,相当于给读操作和写操作都加锁了。但可能出现幻读
4)serializable 串行化 让所有事务串行执行,数据最靠谱
使用
start transaction; --执行事务之前,开启事务
commit; --告诉服务器,事务完毕
rollback; --告诉服务器要进行回滚