mysql数据库总结
事务和ACID
mysql只有在InnoDB引擎下是支持事务的,MyISAM是不支持事务的。
事务具有ACID(原子性,一致性,隔离性,持久性)
原子性 + 隔离性 + 持久性 是为了满足一致性
只有保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。也就是说 A、I、D 是手段,C 是目的!
- 无并发时,只需要保证原子性就能满足一致性
- 有并发时,还需要保证隔离性才能满足一致性
- 持久性是为了应对数据库宕机的情况
事务的隔离级别
MySQL有四种事务隔离级别:读未提交,读提交,可重复读,序列化。(可重复读是默认的隔离级别)
对应事务会发生的问题有三种:脏读,不可重复读,幻读(都发生在多线程下)
三种问题含义如下
- 脏读:事务A读到的num数据,是事务B修改后还没提交的数据
- 丢失修改(Lost to modify):ab事务都访问了同一数据,在a事务中修改了这个数据后,b事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。
- 不可重复读:事务A读到的num数据后,事务B修改了num数据并提交,A此时再读num会发生和第一次读不一致的情况
- 幻读:和不可重复读类似,只不过此时B事务是insert了新的行,A事务读到了和第一次不一样数量的结果。
- 读未提交:都不能解决
- 读提交:可以解决脏读
- 可重复读:可以解决不可重复读
- 序列化:解决幻读
读未提交和串行化基本上是不需要考虑的隔离级别,前者不加锁限制,后者相当于单线程执行,效率太差。
并发事务的控制方法
MySQL 中并发事务的控制方式有两种:锁 和 MVCC(多版本并发控制,Multiversion concurrency control)
- 锁的分类
- 行级锁,表级锁(innoDB支持行级锁,粒度小,并发性能好。MyISAM只支持表级锁)
- 行级锁是针对索引字段的,如果没有命中唯一索引,或者索引失效,那么会导致对所有记录加锁
- 共享锁,排他锁(一般是读锁和写锁)
- MVCC是对同一个数据有存储多个版本,通过事务的可见性保证事务只能看见自己对应的版本。
- MVCC是依赖隐藏字段,Read View,undo log实现的
- undo log用于记录某行数据的多个版本
- read view和隐藏字段用来判断当前版本对数据是否可见
MyISAM 和 InnoDB 有什么区别?
- 是否支持行级锁
- MyISAM只支持表级锁,InnoDB支持行级锁
- 是否支持事务
- MyISAM不支持,InnoDB支持
- 是否外键
- MyISAM不支持,InnoDB支持
- 索引的实现不同
- 虽然 MyISAM 引擎和 InnoDB 引擎都是使用 B+Tree 作为索引结构,但是两者的实现方式不太一样。
- InnoDB 引擎中,其数据文件本身就是索引文件。
- MyISAM,索引文件和数据文件是分离的。
- 是否支持数据库异常崩溃后的安全恢复
- InnoDB通过redo log支持
- MyISAM不支持
mysql的索引数据结构
mysql为了加快数据的查找,引入了索引。
对于一张表的某个字段建立索引之后,当以此列作为查询条件时,可以加速查询。
mysql索引底层数据结构有B+树,Hash索引,Full-text索引,和R-tree索引。(不止有b+tree索引) 不过默认使用的是B+树索引,可以在创建表的时候指定索引类型。
哈希索引
哈希索引适合用于等值查询非常频繁的场景,比如一些简单的查询场景。哈希索引不能支持范围查询、模糊查询等其他类型的查询操作,而且哈希索引无法避免哈希冲突,会降低查询效率。在处理大量数据时,哈希索引的性能会受到影响。
Full-text索引
全文索引,只支持innodb和myisam引擎
R-树索引
R-树索引只支持MyISAM和InnoDB引擎,不支持其他引擎。
B+树索引
B+树是b树的一种升级,b+树的非叶子节点不包括数据本身,所以每次查询都需要查询到叶子节点,b+树的叶子节点是一条链表,可以加快范围查询的速率。
因为b+树的非叶子节点中没有数据本身,所以一个节点可以包含多个子节点,导致b+树比传统的b树要更为矮胖一些,减少数据库查询的io次数
mysql的索引分类
按照存储方式分
- 聚簇索引(聚集索引):索引和数据存放在一起,InnoDB中的主键索引就属于聚簇索引
- 优点:查询快
- 缺点:更新代价大,依赖有序添加
- 非聚簇索引: 索引和数据分开存放,二级索引就是非聚簇索引。MyISAM引擎的索引都是非聚簇索引
- 非聚簇索引查询到对于的主键id后,需要回表到主键索引中查询对应的数据。当此非聚簇索引是覆盖索引时,不需要回表。
- 优点:更新代价小
- 缺点:可能会二次查询(回表)
按照索引状态分
- 主键索引:列值唯一且不能为NULL,每张表只能有一个主键索引
如果一张表没有声明主键索引,mysql会生成一个隐藏列作为主键索引 - 普通索引:加快查询
- 唯一索引:列值为一(可以为null),每张表可以有多个唯一索引
- 覆盖索引:一个索引包含(或者说覆盖)所有需要查询的字段的值。
- 联合索引:多个列值组合成一个索引,用于组合搜索
- 全文所有:对内容进行分词搜索。
mysql的三大日志
mysql包含redo log,undo log和bin log
bin log:他记录了每一个对数据库表和数据库数据的增删改操作,用于主从复制和主从备份等用途
redo log:
在讲redo log之前,先讲述一下mysql读取的背景
mysql的数据是以数据页为单位存储的,对于每次查询,mysql会将整个数据页查询出来。为了加快每次的查询,对于之前已经查询的数据页,会放在缓存中,如果缓存没命中,才会去查询数据库。
那么就出现了一个问题:如果有修改此页数据的操作,那么是修改缓存还是数据库本身?
redo log就应运而生了,对于修改操作,我们只修改在缓存中的数据页,并不修改数据库本身。但是会在redo log结尾添加此操作,到时将redo log中的修改刷盘到数据库中。
因为每次我们修改的数据可能只有几B大小,那么每次去修改16kb的数据页是不现实的。修改数据库是随机读取和写入,在redo log后追加是顺序写入,更快。
undo log:主要用于实现事务的回滚,实现MVCC
对于每次事务,undo log记录于修改操作相反的操作,如果需要回归事务,那么就按照undo log将数据库恢复。
实现MVCC时,根据每个事务的可见性不同,达到多版本控制。