索引
InnoDB
MySQL5.6版本之后默认引擎是innoDB,以B+树作为索引的数据存储结构。
B+数是以B树为基础的另一种更适合数据库存储的数据结构。
-
B树
B树是一个平衡多叉数,结构如图
图1 B树
因为是多叉,相比平衡二叉树而言,能用更少的层存储更多的数据。
-
B+树
B+树是B树的进化。区别在于,B+树的所有数据均存储在叶子节点上,根节点和子节点不存储数据,这样做的好处是根节点和子节点的内容最小化,只用存储索引值和指针即可。
图2 B+树
传统平衡二叉树,需要反复读取多次才能取到叶子节点的数据。而因为磁盘每次IO读取最小均为4K数据,则会产生极大的浪费。4K数据里,差不多能放1200个节点。所以对于一个有1200个节点的B+树,存储10亿级别的数据也就三层结构。磁盘读取3次即可。
主键索引、非主键索引
像图2,或图3第一个这种,叶子节点上挂载具体数据的索引,被称为主键索引。主键索引又叫聚簇索引

图3中,我们用R来表示一条数据,数据至少包含有ID和k两个字段,上面分别有自己的索引。
图3第二个中,以k值做索引,叶子节点上存储的是ID的值,这种被称为非主键索引。
可以看到,真正的数据R本身,是存在主键索引ID的叶子节点上的,在非主键的叶子节点上只存储一个指向ID的指针即可。
假如我们要查找k=5的值,通过k的索引,我们找到k=5的数据的ID=500,然后我们再在ID索引里查找ID=500的数据,最后找到数据R4。 这一过程被称为回表。
从图中可以理解到,一个表里主键索引只有一个,非主键索引可以有多个。
在大多数情况下,数据里最好包含一个自增的主键,也就是唯一的聚簇索引。
覆盖索引
上文已经讲过,如果执行select * from T where k=5
这一条语句,会先通过k=5的索引查出需要的数据的ID=500,然后回表,在主键索引上查询ID=500的值为R4。
如果是select ID from T where k=5
,在第一次查询k=5的索引时,就查出来了ID=500,此时就已经取到了需要的数据,不需要回表,这种情况被称为覆盖索引。覆盖索引是一种常用的性能优化手段。
联合索引,最左前缀法则。
以姓名和年龄做联合索引

在图4中,如果查询... like 张%
,那么此索引是没问题的,会迅速查到姓张的人。但如果是...age=10...
那么此索引无效,依然会全盘扫描数据。
索引下推
在图4中,查询语句为...name like 张% and age=10...
,在MySQL5.6之前,会先查出所有姓张的,然后一个个回表判断age是否=10。5.6引入了索引下推的优化,简单的说就是在查找姓张的数据的时候,直接也判断一下联合索引里的数据age是否等于10。避免了多余的回表。
ACID(原子性、一致性、隔离性、持久性)
隔离性
事务的隔离分级别从松要严可以分为读未提交、读提交、可重复读、串行化。隔离越严,效率越低。
- 读未提交
读未提交是指,一个事物还没提交时,它做的变更就能被别的事物看到。 - 读提交
读提交是指,一个事物提交后,他做的变更才能被别的事物看到。
读提交可以解决脏读问题。 - 可重复读
可重复读是指,一个事物在执行过程中看到的数据总和这个事物在开始时看到的数据是一致的,也就是说一个事物一旦开始了,多次读书数据的值均一致,即可重复读。
可重复读可以解决脏读和不可重复读问题。但不能解决脏读问题。
MySQL默认隔离级别为此级别。
MySQL里,在快照读情况下,通过MVCC等解决了不可重复读的问题。在当前读情况下,通过行锁和间隙锁解决不可重复读问题。 -
串行化
串行化是指,对于同一行记录,写会加锁,读也会加读锁。当执行的操作被锁的时候,只能依次等待锁放开。
串行化性能最慢,但能解决脏读,不可重复读,幻读等问题。
图5 事物隔离
在读未提交的隔离下,V1的值为2,因为可以读到事物B的未提交修改。
在读提交的情况下,V1的值为1,V2的值为2。因为只有在提交了事物B后事物A才能读到数据。
在可重复读的情况下,V1=V2=1,V3的值为2。
在串行化情况下,事物B执行修改语句时,只能等待事物A结束,才能执行。
网友评论