《高性能MySQl》读书笔记
#阅读#
一、MySQL架构
MySQL逻辑架构
第一章的内容主要是以MySql的架构来展开描述的。首先介绍MySql的逻辑架构:

逻辑架构可以分为三层:
- 客户端:这一层不是MySQL独有的,大多数基于网络的客户端/服务器工具或者服务器都有,功能包括连接处理、身份验证、确保安全。
- Server层:大多数MySQL的核心功能都在这一层,包括连接器、查询缓存(MySQl5.7.20版本开始,查询缓存已经被官方弃用,并在8.0版本中被完全移除)、分析器、优化器、执行器等,以及所有内置函数(例如:日期、时间、数字和加密函数),所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。
- 存储引擎层:负责MySql中数据的存储和提取。支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。存储引擎层还包含了十几个底层函数,用于执行像“开始一个事务”或者“根据主键提取一个行记录”等操作。存储引擎不会去解析SQL(InnoDB除外),不同存储引擎不会去通信,只能简单的响应服务器的请求。
并发控制
MySQl提供两个级别的并发控制:服务器级别和存储引擎级别。
解决并发控制的问题,可以通过实现一个由两个锁类型组成的锁系统。这两个锁通常被称为共享锁(读锁)和排它锁(写锁)。
MySQL提供多种选择,每种存储引擎都可以实现自己的锁策略和锁粒度。在设计存储引擎时,锁粒度固定在某个级别,可以提高某个场景下的性能,但是同时又不适应另外的一些场景。但是MySQl提供了多个存储引擎,使得可以适用于各个场景。
表锁
- 是最基本的也是开销最小的锁策略。它是锁定整张表,当客户端需要对表进行写操作时,需要先获取一个写锁,这会阻塞其他客户端对该表的读操作和写操作。只有没有写操作后,其他客户端才能获得读锁,读锁之间不会相互阻塞。
行级锁
- 可以很大程度的支持并发处理,但是带来了最大的开销。行级锁是锁定表中某一行数据,允许其他人编辑其他行,而不会发生阻塞。
事务
- 事务就是一组SQL语句。如果数据库引擎能够成功地对数据库应用整组语句,那么就执行这组语句,如果有其中任意一条语句无法执行,那么整组语句都不执行。简单理解:语句要么都执行,要么都不执行。
- 一个事务处理系统,必须满足ACID。ACID分别为原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)。
原子性:
- 单个事务为一个不可分割的最小工作单元。整个事务中的所有操作要么全部commit成功,要么全部失败rollback,对于一个事务来说,不可能只执行其中的一部分SQL操作,这就是事务的原子性。
一致性:
- 数据库总是从一个一致性的状态转换到另外一个一致性的状态。
隔离性:
- 通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。
持久性:
- 一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。
ACID事务和InnoDB引擎提供的保证是MySQL中最强大、最成熟的特性之一。
隔离级别
一共有四个隔开级别:
- READ UNCOMMITTED(读未提交)
- 在事务中可以查看其他事务中还没有提交的修改。(在实际应用中很少使用)
- READ COMMITTED(读已提交)
- 大部分数据库系统默认的隔离级别就是READ COMMITTED(但是MySQl不是)。一个事务可以看到其他事务在它开始之后提交的修改,但在该事务提交之前,其所作的任何修改对其他事务都是不可见的。但是这个级别还是允许不可重复读,这意味着同一个事务中两次执行相同的语句,可能看到不同的数据结果。

- REPEATABLE READ(可重复读)
- REPEATABLE READ是MySQL数据库默认的事务隔离级别。解决了READ COMMITTED级别不可重复读的问题,保证了在同一个事务中读取到的行数据的结果是一样的。但是无法解决幻读问题。所谓幻读指的是读取某一个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取到该范围的记录时,会产生幻行(InnoDB和XtraDB存储引擎通过多版本并发控制解决幻读问题)。
- SERIALIZABLE(可串行化)
- SERIALIZABLE是最高的隔离级别。SERIALIZABLE会在读取的每一条数据上加锁,所以可能导致大量的超时和锁争用的问题。实际应用中很少使用此隔离级别。
设置隔离级别
- 设置全局隔离级别:
- 设置会话隔离级别:
死锁
死锁是指两个或者多个事务相互持有和请求相同的资源上的锁,产生的循环依赖。当多个事务试图以不同的顺序锁定资源时会导致死锁。当多个事务锁定相同的资源时,也可能会发生死锁。
举例:
- 每个事务都开始执行第一个查询,在处理过程中会更新一行数据,同时在主键索引和其他唯一索引中将该行锁定。然后,每个事务将在第二个查询中尝试更新第二行数据,却发现该行已经被锁定。这两个事务将永远等待对方完成,除非有其他因素介入解除死锁。这就是一个典型的死锁。
- 为了解决这个问题,数据库实现了各种死锁检测和锁超时机制。InnoDB目前处理死锁的方式是将持有最少行级写锁的事务回滚。
- 锁的行为和顺序是和存储引擎有关。同样的一系列查询语句,有的存储引擎会产生死锁,有些则不会。
- 死锁产生的原因(两个):一个是真正的数据冲突。另一个是存储引擎的实现方式导致的。.
事务日志
事务日志有助于提高事务效率。存储引擎只需要更改内容中的数据副本,而不用每次更改磁盘中的表,然后再把更改记录写入事务日志中,事务日志会被持久化保存在硬盘中。最后会有一个后台进程在某个时间去更新硬盘中的表。
MySql中的事务
AUTOCOMMIT
- 默认情况下,单个INSERT、UPDATE或DELETE语会被隐式包装在一个事务中并在执行成功后立即提交,这称为自动提交 (AUTOCOMMIT) 模式。通过禁用此模式,可以在事务中执行一系列语句,并在结束时执行COMMIT提交事务或 ROLLBACK 回滚事务。
- 在当前连接中,可以使用SET命令设置AUTOCOMMIT变量来启用或禁用自动提交模式。启用可以设置为1或者ON,禁用可以设置为0或者OFF。如果设置了AUTOCOMMIT=0,则当前连接总是会处于某个事务中,直到发出COMMIT或者ROLLBACK,然后MySQL会立即启动一个新的事务。
注意:
- 不要在同一个事务中混合使用存储引擎。失败的事务可能导致不一样的结果。因为某些部分可以回滚,而其他部分不可以回滚。
隐式锁定和显式锁定
- InnoDB使用两阶段锁定协议(two-phase locking protocol)。在事务执行期间,随时都可以获取锁,但锁只有在提交或回滚后才会释放,并且所有的锁会同时释放。InnoDB会根据隔离级别自动处理锁。
- MySQL还支持LOCK TABLES 和UNLOCK TABLES命令,这些命令在服务器级别而不在存储引擎中实现。如果需要事务,应该使用支持事务的存储引擎。因为InnoDB支持行级锁,所以没必要使用LOCK TABLES。
- 注意:
- 除了在禁用AUTOCOMMIT的事务中可以使用LOCK TABLES之外,其他任何时候都不要显式地执行 LOCK TABLES,不管使用的是什么存储引擎。
多版本并发控制(MVCC)
MVCC(Multiversion Concurrency Control),多版本并发控制。MVCC是通过数据行的多个版本管理来实现数据库的并发控制。它的工作原理是使用数据在某个时间点的快照来实现的。这项技术使得在InnoDB的事务隔离级别下执行 一致性读操作有了保证。这意味着不同事务可以在同一个时间看到同一张表的不同数据,换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值,这样在做查询的时候就不用等待另一个事务释放锁。
跨不同事务处理同一行多个版本的序列图:

- InnoDB通过为每个事务在启动时分配一个事务ID来实现MVCC。该ID在事务首次读取任何数据时分配。在该事务中修改记录时,将向Undo日志写入一条说明如何恢复该更改的Undo记录,并且事务的回滚指针指向该 Undo日志记录。这就是事务如何在需要时执行回滚的方法。
- 当不同的会话读取聚簇主键索引记录时,InnoDB会将该记录的事务ID与该会话的读取视图进行比较。如果当前状态下的记录不应可见(更改它的事务尚未提交),那么Undo日志记录将被跟踪并应用,直到会话达到一个符合可见条件的事务ID。这个过程可以一直循环到完全删除这一行的Undo记录,然后向读取视图发出这一行不存在的信号。
注意:
- MVCC仅适用于REPEATABLE READ和READ COMMITTED隔离级别。READ UNCOMMITTED与MVCC不兼是因为查询不会读取适合其事务版本的行版本,而是不管怎样都读最新版本。SERIALIZABLE与MVCC也不兼容,是因为读取会锁定它们返回的每一行。
复制
- MySOL被设计用于在任何给定时间只在一个节点上接受写操作。这在管理一致性方面具有优势,但在需要将数据写入多台服务器或多个地区时,会导致需要做出取舍。MySQL 提供了一种原生方式来将一个节点执行的写操作分发到其他节点,这被称为复制。在MySQL中,源节点为每个副本节点提供一个线程,该线程作为复制客户端登录当写入发生时会被唤醒,发送新数据。
- 对于在生产环境中运行的任何数据,都应该使用复制并至少有三个以上的副本,理想情况下应该分布在不同的地区用于灾难恢复计划。
InnoDB引擎
- InnoDB是MySQL默认的通用存储引擎。默认情况下,InnoDB将数据存储在一系列的数据文件中,这些文件统被称为表空间 (tablespace)。表空间本质上是一个由InnoDB自己管理的黑盒。
- InnoDB使用MVCC来实现高并发性,并实现了所有4个SOL标准隔离级别。InnoDE默认为REPEATABLE READ隔离级别,并且通过间隙锁 (next-key locking)策略来防止在这个隔离级别上的幻读 :InnoDB 不只锁定在查询中涉及的行,还会对索引结构中的间隙进行锁定,以防止幻行被插入。
JSON文档支持
- ISON类型在5.7版本被首次引人InnoDB,它实现了JSON文档的自动验证,并优化了存储以允许快速读取。
- InnoDB还引入了SQL函数来支持在JSON 文档上的丰富操作。MySOL8.0.7的进一步改进增加了在JSON数组上定义多值索引的能力。将常用访问模式匹配到可以映射JSON文档值的函数这一特性可以进一步加快对JSON类型的读取访问查询。


