《高性能MySQl》读书笔记

#阅读#

一、MySQL架构


MySQL逻辑架构


第一章的内容主要是以MySql的架构来展开描述的。首先介绍MySql的逻辑架构:

逻辑架构可以分为三层:

  1. 客户端:这一层不是MySQL独有的,大多数基于网络的客户端/服务器工具或者服务器都有,功能包括连接处理、身份验证、确保安全。
  2. Server层:大多数MySQL的核心功能都在这一层,包括连接器、查询缓存(MySQl5.7.20版本开始,查询缓存已经被官方弃用,并在8.0版本中被完全移除)、分析器、优化器、执行器等,以及所有内置函数(例如:日期、时间、数字和加密函数),所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。
  3. 存储引擎层:负责MySql中数据的存储和提取。支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。存储引擎层还包含了十几个底层函数,用于执行像“开始一个事务”或者“根据主键提取一个行记录”等操作。存储引擎不会去解析SQL(InnoDB除外),不同存储引擎不会去通信,只能简单的响应服务器的请求。


并发控制


MySQl提供两个级别的并发控制:服务器级别和存储引擎级别。


解决并发控制的问题,可以通过实现一个由两个锁类型组成的锁系统。这两个锁通常被称为共享锁(读锁)和排它锁(写锁)。


MySQL提供多种选择,每种存储引擎都可以实现自己的锁策略和锁粒度。在设计存储引擎时,锁粒度固定在某个级别,可以提高某个场景下的性能,但是同时又不适应另外的一些场景。但是MySQl提供了多个存储引擎,使得可以适用于各个场景。


表锁


  1. 是最基本的也是开销最小的锁策略。它是锁定整张表,当客户端需要对表进行写操作时,需要先获取一个写锁,这会阻塞其他客户端对该表的读操作和写操作。只有没有写操作后,其他客户端才能获得读锁,读锁之间不会相互阻塞。


行级锁


  1. 可以很大程度的支持并发处理,但是带来了最大的开销。行级锁是锁定表中某一行数据,允许其他人编辑其他行,而不会发生阻塞。


事务


  1. 事务就是一组SQL语句。如果数据库引擎能够成功地对数据库应用整组语句,那么就执行这组语句,如果有其中任意一条语句无法执行,那么整组语句都不执行。简单理解:语句要么都执行,要么都不执行。
  2. 一个事务处理系统,必须满足ACID。ACID分别为原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)。

原子性:


  1. 单个事务为一个不可分割的最小工作单元。整个事务中的所有操作要么全部commit成功,要么全部失败rollback,对于一个事务来说,不可能只执行其中的一部分SQL操作,这就是事务的原子性。


一致性:


  1. 数据库总是从一个一致性的状态转换到另外一个一致性的状态。


隔离性:


  1. 通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。


持久性:


  1. 一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。


ACID事务和InnoDB引擎提供的保证是MySQL中最强大、最成熟的特性之一。


隔离级别


一共有四个隔开级别:

  1. READ UNCOMMITTED(读未提交)
  2. 在事务中可以查看其他事务中还没有提交的修改。(在实际应用中很少使用)
  3. READ COMMITTED(读已提交)
  4. 大部分数据库系统默认的隔离级别就是READ COMMITTED(但是MySQl不是)。一个事务可以看到其他事务在它开始之后提交的修改,但在该事务提交之前,其所作的任何修改对其他事务都是不可见的。但是这个级别还是允许不可重复读,这意味着同一个事务中两次执行相同的语句,可能看到不同的数据结果。
  5. REPEATABLE READ(可重复读)
  6. REPEATABLE READ是MySQL数据库默认的事务隔离级别。解决了READ COMMITTED级别不可重复读的问题,保证了在同一个事务中读取到的行数据的结果是一样的。但是无法解决幻读问题。所谓幻读指的是读取某一个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取到该范围的记录时,会产生幻行(InnoDB和XtraDB存储引擎通过多版本并发控制解决幻读问题)。
  7. SERIALIZABLE(可串行化)
  8. SERIALIZABLE是最高的隔离级别。SERIALIZABLE会在读取的每一条数据上加锁,所以可能导致大量的超时和锁争用的问题。实际应用中很少使用此隔离级别。


设置隔离级别


  1. 设置全局隔离级别:


set global transaction isolation level 隔离级别


  1. 设置会话隔离级别:


set session transaction isolation level 隔离级别


死锁


死锁是指两个或者多个事务相互持有和请求相同的资源上的锁,产生的循环依赖。当多个事务试图以不同的顺序锁定资源时会导致死锁。当多个事务锁定相同的资源时,也可能会发生死锁。

举例:

START TRANSACTION;
UPDATE StockPrice SET close = 45.50 WHERE stock id = 4 and date =2020-05-01';
UPDATE StockPrice SET close = 19.80 WHERE stock_id = 3 and date =2020-05-02;
COMMIT;


START TRANSACTION;
UPDATE StockPrice SET high = 20.12 WHERE stock_id = 3 and date =  2020-05-02;
UPDATE StockPrice SET high = 47.20 WHERE stock_id = 4 and date = 2020-05-01';
COMMIT;


  1. 每个事务都开始执行第一个查询,在处理过程中会更新一行数据,同时在主键索引和其他唯一索引中将该行锁定。然后,每个事务将在第二个查询中尝试更新第二行数据,却发现该行已经被锁定。这两个事务将永远等待对方完成,除非有其他因素介入解除死锁。这就是一个典型的死锁。
  2. 为了解决这个问题,数据库实现了各种死锁检测和锁超时机制。InnoDB目前处理死锁的方式是将持有最少行级写锁的事务回滚。
  3. 锁的行为和顺序是和存储引擎有关。同样的一系列查询语句,有的存储引擎会产生死锁,有些则不会。
  4. 死锁产生的原因(两个):一个是真正的数据冲突。另一个是存储引擎的实现方式导致的。.


事务日志


事务日志有助于提高事务效率。存储引擎只需要更改内容中的数据副本,而不用每次更改磁盘中的表,然后再把更改记录写入事务日志中,事务日志会被持久化保存在硬盘中。最后会有一个后台进程在某个时间去更新硬盘中的表。


MySql中的事务


AUTOCOMMIT


  1. 默认情况下,单个INSERT、UPDATE或DELETE语会被隐式包装在一个事务中并在执行成功后立即提交,这称为自动提交 (AUTOCOMMIT) 模式。通过禁用此模式,可以在事务中执行一系列语句,并在结束时执行COMMIT提交事务或 ROLLBACK 回滚事务。
  2. 在当前连接中,可以使用SET命令设置AUTOCOMMIT变量来启用或禁用自动提交模式。启用可以设置为1或者ON,禁用可以设置为0或者OFF。如果设置了AUTOCOMMIT=0,则当前连接总是会处于某个事务中,直到发出COMMIT或者ROLLBACK,然后MySQL会立即启动一个新的事务。


注意:


  1. 不要在同一个事务中混合使用存储引擎。失败的事务可能导致不一样的结果。因为某些部分可以回滚,而其他部分不可以回滚。


隐式锁定和显式锁定


  1. InnoDB使用两阶段锁定协议(two-phase locking protocol)。在事务执行期间,随时都可以获取锁,但锁只有在提交或回滚后才会释放,并且所有的锁会同时释放。InnoDB会根据隔离级别自动处理锁。
  2. MySQL还支持LOCK TABLES 和UNLOCK TABLES命令,这些命令在服务器级别而不在存储引擎中实现。如果需要事务,应该使用支持事务的存储引擎。因为InnoDB支持行级锁,所以没必要使用LOCK TABLES。
  3. 注意:
  4. 除了在禁用AUTOCOMMIT的事务中可以使用LOCK TABLES之外,其他任何时候都不要显式地执行 LOCK TABLES,不管使用的是什么存储引擎。


多版本并发控制(MVCC)


MVCC(Multiversion Concurrency Control),多版本并发控制。MVCC是通过数据行的多个版本管理来实现数据库的并发控制。它的工作原理是使用数据在某个时间点的快照来实现的。这项技术使得在InnoDB的事务隔离级别下执行 一致性读操作有了保证。这意味着不同事务可以在同一个时间看到同一张表的不同数据,换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值,这样在做查询的时候就不用等待另一个事务释放锁。

跨不同事务处理同一行多个版本的序列图:

  1. InnoDB通过为每个事务在启动时分配一个事务ID来实现MVCC。该ID在事务首次读取任何数据时分配。在该事务中修改记录时,将向Undo日志写入一条说明如何恢复该更改的Undo记录,并且事务的回滚指针指向该 Undo日志记录。这就是事务如何在需要时执行回滚的方法。
  2. 当不同的会话读取聚簇主键索引记录时,InnoDB会将该记录的事务ID与该会话的读取视图进行比较。如果当前状态下的记录不应可见(更改它的事务尚未提交),那么Undo日志记录将被跟踪并应用,直到会话达到一个符合可见条件的事务ID。这个过程可以一直循环到完全删除这一行的Undo记录,然后向读取视图发出这一行不存在的信号。


注意:


  1. MVCC仅适用于REPEATABLE READ和READ COMMITTED隔离级别。READ UNCOMMITTED与MVCC不兼是因为查询不会读取适合其事务版本的行版本,而是不管怎样都读最新版本。SERIALIZABLE与MVCC也不兼容,是因为读取会锁定它们返回的每一行。


复制


  1. MySOL被设计用于在任何给定时间只在一个节点上接受写操作。这在管理一致性方面具有优势,但在需要将数据写入多台服务器或多个地区时,会导致需要做出取舍。MySQL 提供了一种原生方式来将一个节点执行的写操作分发到其他节点,这被称为复制。在MySQL中,源节点为每个副本节点提供一个线程,该线程作为复制客户端登录当写入发生时会被唤醒,发送新数据。
  2. 对于在生产环境中运行的任何数据,都应该使用复制并至少有三个以上的副本,理想情况下应该分布在不同的地区用于灾难恢复计划。


InnoDB引擎


  1. InnoDB是MySQL默认的通用存储引擎。默认情况下,InnoDB将数据存储在一系列的数据文件中,这些文件统被称为表空间 (tablespace)。表空间本质上是一个由InnoDB自己管理的黑盒。
  2. InnoDB使用MVCC来实现高并发性,并实现了所有4个SOL标准隔离级别。InnoDE默认为REPEATABLE READ隔离级别,并且通过间隙锁 (next-key locking)策略来防止在这个隔离级别上的幻读 :InnoDB 不只锁定在查询中涉及的行,还会对索引结构中的间隙进行锁定,以防止幻行被插入。


JSON文档支持


  1. ISON类型在5.7版本被首次引人InnoDB,它实现了JSON文档的自动验证,并优化了存储以允许快速读取。
  2. InnoDB还引入了SQL函数来支持在JSON 文档上的丰富操作。MySOL8.0.7的进一步改进增加了在JSON数组上定义多值索引的能力。将常用访问模式匹配到可以映射JSON文档值的函数这一特性可以进一步加快对JSON类型的读取访问查询。




0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
稚屿
下载 APP