Mysql详解脉络

1、存储引擎的选择

1.1 Innodb

选择innodb作为存储引擎主要有三点原因:

  1. 独立表空间,支持事物,通过MVCC、行锁设计,提供一致性非锁定读
  2. 支持外键,插入缓冲,二次写,自适应哈希索引,预读
  3. 使用聚集的方式存储数据,每张表的存储都是按主键顺序存放。
  4. 备份:InnoDB 支持在线热备份

1.2 MyISAM

MyISAM引擎的特点:

  1. 只支持表级锁,用户在操作myisam表时,select,update,selete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据
  2. 崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。
  3. 其它特性:MyISAM 支持压缩表和空间数据索引。

2、 事物

2.1 事务的特性

  • 原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
  • 一致性(Consistent) :在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
  • 隔离性(Isolation) :数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
  • 持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

2.2 Innodb如何保证事物的特性

  • 原子性(Atomicity)undo log支持事物的回滚,保证事物内操作的原子性
  • 一致性(Consistent) :多数说法,一致性是应用层语义上的前后一致,也就是说,是业务层面对执行的结果符合预期。所以,一般来说,一致性是通过其他三个特性来保证的
  • 隔离性(Isolation) :通过mvcc和锁来保证事物隔离性
  • 持久性(Durable)redo log重做日志保证

2.3 并发事物可能带来的问题

更新丢失(Lost Update)
  当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。
脏读(Dirty Reads)
  一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致的状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此作进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象的叫做“脏读”。一句话:事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求。
不可重读(Non-Repeatable Reads)
  一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”。一句话:事务A读取到了事务B已经提交的修改数据,不符合隔离性
幻读(Phantom Reads)
  一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。一句话:事务A读取到了事务B提交的新增数据,不符合隔离性

2.4 事物隔离级别及实现

  • 读未提交
  • 读已提交
  • 可重复读
  • 串行化

2.5 并发事物问题的解决

隔离级别与对应问题处理
可重复读隔离级别的幻读问题:
  • 如果事物A仅执行快照读的查询语句多次,且中间为插入任何当前读语句,则查询结果一定满足可重复读(mvcc保证了在A事物查询之后创建的事物影响不到A,通过undo log实现的)
  • 幻读特殊情况:事物A查询当前值为1,其他事物进行+1操作。此时A查询结果不变。然后A执行+1操作,查询后发现数值总共+2。这是因为update相当于当前读,所以查到了其他事物提交的结果。这也是并发执行有可能会出现问题的地方(是否有问题视业务具体情况)。如果要解决就需要用到行锁、间隙锁了。

2.6 间隙锁

定义:间隙锁是对索引记录之间间隙的锁,或者是对第一个或最后一个索引记录之前或之后的间隙的锁

3、索引

3.1 Innodb选择B+树作为索引的原因

  1. 树高相对较低:树高度决定数据页加载次数,应该尽量少来提高查询速度
  2. 适合范围查找:叶子节点联通,适合进行范围查找

3.2 B+树结构

B+树是B树的一种变形形式,B+树上的叶子结点存储关键字以及相应记录的地址,叶子结点以上各层作为索引使用。一棵m阶的B+树定义如下
(1)每个结点至多有m个子女;
(2)除根结点外,每个结点至少有[m/2]个子女,根结点至少有两个子女;
(3)有k个子女的结点必有k个关键字。

B+树的查找与B树不同,当索引部分某个结点的关键字与所查的关键字相等时,并不停止查找,应继续沿着这个关键字左边的指针向下,一直查到该关键字所在的叶子结点为止

3.3 聚簇索引、非聚簇索引,非聚簇不存行的原因

  • 聚簇索引:叶子节点记录行数据的索引
  • 非聚簇索引:聚簇索引只能有一个,其他的都是非聚簇。叶子节点记录聚餐索引的值
  • 非聚簇不存行的原因:个人理解,行数据被聚簇索引按照索引顺序维护到了对应的页里,如果非聚簇也直接记录行数据,只能冗余出一份文件,浪费空间;如果记录行地址,有个很严重的问题,是行地址是会发送改变的(不按顺序插入或删除,导致页分裂或者合并),这种时候,就需要在改变地址时同时修改所有索引,耗费性能。

3.4 唯一索引和普通索引的选择

  1. 查询过程:
    普通索引,查找到满足条件的第一个记录(5,500)后,需要查找下一个记录,直到碰到第一个不满足k=5条件的记录。
    唯一索引:由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。
  2. 更新过程:
    唯一索引:所有的更新操作都要先判断这个操作是否违反唯一性约,而这必须要将数据页读入内存才能判断
    普通索引:如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB会将这些更新操作缓存在change buffer中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行change buffer中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。因此,在更新普通索引时,若对应的数据页不在内存,就通过change buffer的机制,减少磁盘Io

4、日志

4.0 MVCC

4.1 redo log

3.2 undo log

3.3 二阶段提交

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容