第一章—MySQL架构与历史
MySQL逻辑架构
- 第一层是客户端连接,例如mysql命令行工具
- 第二层是MySQL核心服务
- 第三层是存储引擎,负责数据的存储与提取
优化与执行
- MySQL会解析查询,并创建内部数据结构(解析树),然后对其进行优化,例如:重写查询、决定表的读取顺序、选择合适的索引等。
- 并发控制
- MySQL在服务器层与存储引擎层处理并发
- 通过加锁的方式来解决资源竞争:表锁与行级锁
- 表锁:锁定整张表。用户在对表进行写操作(插入、删除、更新)的时候,会先获得表的写锁(其他用户被阻塞),操作结束后(commit)会自动释放写锁。但,要是用户获取的是读锁,就不会阻塞其他用户。只有拿到写锁的时候,既会阻塞其他用户的写,又会阻塞读。
- 行级锁:锁定某一行。MySQL只在存储引擎层实现,没有在服务器层实现。
- 只有在你增删改查时匹配的条件字段带有索引,innodb才会使用行级锁,在你增删改查时匹配的条件字段不带有索引时,innodb使用的将是表级锁。
事务
- 事务就是一组原子性的sql查询。
- 事务的特性:ACID
- 原子性(atomicity)
- 事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
- 回滚可以用日志来实现,日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。
- 一致性(consistency)
- 数据库在事务执行前后都保持一致性状态。
- 在一致性状态下,所有事务对一个数据的读取结果都是相同的
- 隔离性(isolation)
- 一个事务所做的修改在最终提交以前,对其它事务是不可见的。或者说其他事务无法干扰。
- 持久性(durability)
- 只有满足一致性,事务的执行结果才是正确的。
- 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。
- 在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
- 事务满足持久化是为了能应对数据库崩溃的情况。
隔离性的级别
未提交读(READ UNCOMMITTED)
- 在此隔离级别下,对数据进行修改时,即使没有提交数据,其他事务也可以读取本事务,最后导致它读取到了不正确的数据,也就是脏读
- 此隔离级别虽然性能高,但会导致很多问题,一般不使用它
提交读(READ COMMITTED)
- 此隔离级别是大多数数据库系统的默认隔离级别(但MySQL不是的),它从开始到结束对其他事务都是不可见的,其他事务无法干涉
- 有时候也称为不可重复读
可重复读(REPEATABLE READ)
- 同一个事务中多次读取同样数据的结果是一样的
- 这是MySQL的默认隔离级别
- 解决了脏读的问题,但无法解决幻读的问题
- 幻读:A事务读取某表的100行数据,读完后还没继续操作时B对这张表又插入一条新的数据,然后如果A要再次读取这个表的100行数据,但是发现多了一行,就好像出现了幻觉一样。这就叫幻读。
- 幻读是由插入或者删除引起的
可串行化 (SERIALIZABLE)
- 串行执行事务,是最高的隔离级别。
- 一般不使用它。除非要求极高的数据一致性,并且可接受没有并发
并发一致性问题
在并发环境下,事务的隔离性很难保证,因此会出现很多并发一致性问题。
产生并发不一致性问题主要原因是破坏了事务的隔离性,解决方法是通过并发控制来保证隔离性。
并发控制可以通过封锁来实现,但是封锁操作需要用户自己控制,相当复杂。
因此,数据库管理系统提供了事务的隔离级别,让用户以一种更轻松的方式处理并发一致性问题。
丢失修改
- T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。
- 读脏数据 T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。
幻影读
- T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。(幻影读一般是由于增加、删除、更新导致的)
多版本并发控制(MVCC)
- MVCC是行级锁的一种,但是他可以在大多数情况下避免加锁操作,开销更低,而且实现了非阻塞的读操作
- innoDB使用MVCC处理高并发
存储引擎
innoDB
innoDB是 MySQL 默认的事务型存储引擎,只有在需要它不支持的特性时,才考虑使用其它存储引擎。
实现了四个标准的隔离级别,默认级别是可重复读(REPEATABLE READ)。在可重复读隔离级别下,通过多版本并发控制(MVCC)+ 间隙锁(Next-Key Locking)防止幻影读。
主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。
内部做了很多优化,包括从磁盘读取数据时采用的可预测性读、能够加快读操作并且自动创建的自适应哈希索引、能够加速插入操作的插入缓冲区等。
支持真正的在线热备份。其它存储引擎不支持在线热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取
MyISAM
设计简单,数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操作,则依然可以使用它。
提供了大量的特性,包括压缩表、空间数据索引等。
不支持事务。
不支持行级锁,只能对整张表加锁,读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT)。
可以手工或者自动执行检查和修复操作,但是和事务恢复以及崩溃恢复不同,可能导致一些数据丢失,而且修复操作是非常慢的。
如果指定了 DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。
区别
- 事务:InnoDB 是事务型的,可以使用 Commit 和 Rollback 语句。
- 并发:MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。
- 外键:InnoDB 支持外键。
- 备份:InnoDB 支持在线热备份。
- 崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。
- 其它特性:MyISAM 支持压缩表和空间数据索引。