MySQL最重要、最与众不同的特性是它的存储引擎架构,这种架构将查询处理与数据的存储/提取相分离,使得可以在使用时根据不同的需求来选择数据存储的方式。
一、Mysql逻辑架构
如果能在头脑中构建出一幅MySQL各组件之间如何协同工作的架构图,就会有助于深入理解MySQL服务器。
mysql 数据库的逻辑架构如下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jx9utej6-1603348859176)(/Users/marron27/Documents/lizhengi/MySQL/高性能MySQL/T.Mysql逻辑图.png)]
从上图可以看出My SQL逻辑结构大致可以分为三层:
第一层结构主要处理客户端与mysql服务端的连接、授权认证、安全等;
第二层是Mysql服务端的核心,功能包括查询解析、分析、优化、缓存等,所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等都在这一层实现;
第三层的存储引擎主要负责数据存储和提取,服务器通过API与存储引擎进行通信,存储引擎API包含几十个底层函数,用于执行诸如“开始一个事务”或者“根据 主键提取一行记录”等操作。但存储引擎不会去解析sql,不同存储引擎之间不会通讯,只会简单地响应上层服务器的请求
1.1、连接管理
每个客户端连接成功,都会在服务器进程中拥有一个线程,服务器会缓存线程,该线程只能轮流在某个CPU中运行,所以不需要创建和销毁线程。
1.2、安全性
当客户端(应用)连接到MySQL服务器时,服务器需要对其进行认证。认证基于用户名、原始主机信息和密码等信息。
一旦客户端连接成功,服务器会继续验证该客户端是否具有执行某个特定查询的权限
1.3、解析优化查询
MySQL会解析査询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重 写查询、决定表的读取顺序,以及选择合适的索引等。
对于SELECT查询语句,解析查询之前会先查询缓存,如果缓存能找到是不会去解析的,如果缓存查找不到,就会重现解析查询,创建解析树,然后对其进行查询优化、决定表的读取顺序、选择合适的索引等
二、并发控制
无论何时,只要有多个査询需要在同一时刻修改数据,都会产生并发控制的问题。
并发即指在同一时刻,多个操作并行执行。MySQL对并发的处理主要应用了两种机制——是"锁"和"多版本控制"。
2.1、锁机制
在处理并发读或者写时,可以 通过实现一个由两种类型的锁组成的锁系统来解决问题:
- 共享锁:也称为读锁,读锁允许多个连接可以同一时刻并发的读取同一资源,互不干扰;
- 排他锁:也称为写锁,一个写锁会阻塞其他的写锁或读锁,保证同一时刻只有一个连接可以写入数据,同时防止其他用户对这个数据的读写。
2.2、锁粒度
所谓的锁策略,就是在锁的开销和数据的安全性之间寻求平衡,这种平衡当然也会影响到性能。
MySQL提供两个级别的并发控制:服务器级(the server level)和存储引擎级(the storage engine level)。加锁是实现并发控制的基本方法,MySQL中锁的粒度:
- 表级锁(服务器层):MySQL独立于存储引擎提供表锁,例如,对于ALTER TABLE语句,服务器提供表锁(table-level lock)。表锁是最基本也是开销最小的策略;
- 行级锁(引擎层):InnoDB和Falcon存储引擎提供行级锁,此外,BDB支持页级锁。行级锁可以最大程度地支持并发处理(同时也带来了最大的锁开销)。
另外,值得一提的是,MySQL的一些存储引擎(如InnoDB、BDB)除了使用封锁机制外,还同时结合MVCC机制,即多版本并发控制(Multi-Version Concurrent Control),来实现事务的并发控制,从而使得只读事务不用等待锁,提高了事务的并发性。
2.3、多版本并发控制
MVCC的实现:通过保存数据资源在不同时间点的快照实现的。根据事务开始的时间不同,每个事务看到的数据快照版本是不一样的。
InnoDB中的MVCC实现:通过在每行记录后面保存两个隐藏的列来实现,一个保存了行的创建时间,一个保存了行的过期时间。
-
SELECT
当读取记录时,存储引擎会选取满足下面两个条件的行作为读取结果。
读取记录行的开始版本号必须早于当前事务的版本号。也就是说,在当前事务开始之前,这条记录已经存在。在事务开始之后才插入的行,事务不会看到。
读取记录行的过期版本号必须晚于当前事务的版本号。也就是说,当前事务开始的时候,这条记录还没有过期。在事务开始之前就已经过期的数据行,该事务也不会看到。
-
INSERT
存储引擎为新插入的每一行保存当前的系统版本号作为这一行的开始版本号。
-
UPDATE
存储引擎会新插入一行记录,当前的系统版本号就是新记录行的开始版本号。同时会将原来行的过期版本号设为当前的系统版本号。
-
DELETE
存储引擎将删除的记录行的过期版本号设置为当前的系统版本号。
MVCC只在 REPEATABLE READ 和 READ COMMITTED 两个隔离级别下工作。
三、事务
3.1、事务的ACID特性
数据库的事务处理的原则是保证ACID的正确性。
事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性:
- 原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行,不可能只执行其中的一部分。(不可分割)
- 一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。(状态更改一致性)
- 隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的。(执行过程隔离不可见)
- 持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。(持久生效)
3.2、事务处理带来的问题
由于事务的并发执行,带来以下一些著名的问题:
- 更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题--最后的更新覆盖了由其他事务所做的更新。
- 脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些"脏"数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做"脏读"。
- 不可重复读(Non-Repeatable Reads):一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做"不可重复读"。
- 幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为"幻读"。
3.3、Mysql隔离级别
READ UNCOMMITTED :事务可以看到其他事务没有被提交的数据(脏数据)。
READ COMMITTED :事务可以看到其他事务已经提交的数据。
REPEATABLE READ :保证事务中多次查询的结果相同(Innodb默认级别),会出现幻读。
SERIALIZABLE :所有事务顺序执行,对所有read操作加锁。保证一致性。
四、总结
MySQL拥有分层的架构。上层是服务器层的服务和査询执行引擎,下层则是存储引擎。 虽然有很多不同作用的插件API,但存储引擎API还是最重要的。如果能理解MySQL 在存储引擎和服务层之间处理查询时如何通过API来回交互,就能抓住MySQL的核心 基础架构的精髓。
参考:
《高性能 MySQL 第三版》