《高性能MySQL》读书笔记-1-MySQL架构与历史
了解MySQL的服务架构,理解MySQL的设计。MySQL设计时将查询处理(Query Processing)以及其他系统任务(Server Task)和数据的存储、提取分离开,这样的设计带来了极大的灵活性,可以根据需要选择存储引擎。
不满足是向上的齿轮。
— 鲁迅
1.MySQL逻辑架构
- 客户端层:连接处理、授权认证、安全管理等服务
- 核心服务层:查询解析、分析,优化、缓存以及内置函数,以及跨存储引擎的功能:存储过程、触发器、视图等
- 存储引擎层:存储引擎主要实现MySQL中数据的存储和提取。核心服务通过API与储存引擎进行通信。其中,事务、数据提取这样的操作也是由存储引擎这一层来实现的。同时存储引擎不会解析SQL(InnoDB会解析外键定义),只是简单的响应核心服务的请求。
- MySQL8之后不再内置查询缓存。
1.1 连接管理和安全性
连接管理主要负责客户端和MySQL服务的通信:接收请求,传递结果信息。每个客户端连接都会在服务器进程中分配到一个线程,这个连接的查询只会在这个单独的线程中执行。当客户端连接时认证模块会基于用户名、原始主机信息、密码对其连接进行认证,同时也会进行权限校验。
1.2 优化与执行
对于一个查询,MySQL会解析这个查询:创建解析树,并进行重写查询、决定表的读取顺序、选择索引等。
2. 并发控制
2.1 读写锁
MySQL在两个层面进行并发控制:核心服务层和存储引擎层;并发控制可以由共享锁(读锁)和排他(写锁)锁来解决并发问题:
- 读锁是共享的,多个读操作之间互不影响。
- 写锁是排他的,一个写操作会阻塞其他的写锁和读锁。
2.2 锁粒度
尽量只锁定需要修改的部分数据,理想的状态时只对需要修改的数据片进行精确的锁定。为了平衡锁开销和数据安全性,一般是施加行级锁。
表锁(table lock):表锁会锁定整张表,这会阻塞其他用户的所有读写操作。(写锁可以插入到所队列中读锁的前面,读锁却不能插入到写锁之前)
行级锁(row lock):InnoDB存储引擎实现了行级锁,因此InnoDB可以最大程度的支持并发处理。当然也带来了很大的开销。当然了,行级锁是存储引擎层自己实现的,核心服务层并不感知。
3. 事务
事务就是一组原子性的SQL查询,或则一个独立的工作单元:要么事务内的这一组语句一起成功,要么一起失败。
原子性(Atomicity):一个事务被视为不可分割的最小工作单元,一个事务的所有操作要么全部提交成功,要么全部失败回滚。
一致性(Consistency):数据库总是从一个一致的状态到另一个一致的状态。事务没有提交,事务的修改就不会保存到数据库中。
隔离性(isolation):通常来说,一个事务所作的操作在最终提交之前,对其他事务来说是不可见的。
持久性(durability):一旦事务提交,则其所作的修改就会永久的保存到数据库中。
3.1 隔离级别
Read Uncommitted(读未提交)
事务中的修改没有提交对其他事务也是可见的。事务可以读到未提交的数据称为脏读。
Read Committed(读已提交)
一个事务从开始到提交之前,所做的任何修改对他其事务是不可见的。这个级别也叫不可重复读(在同一个事务内多次读取相同范围的记录可能不一致)。
Repetable Read(可重复读)
repeable read解决了脏读的问题,保证了在同一个事务的多次读取同样记录的结果是一致的(在一次事务内)。可重复读不能解决幻读的问题,即同样的事务再次读取同样范围内的记录时,可能会产生幻行(即多次读数据可能不一样)。
Serializable(可串行化)
最高的隔离级别,没有并发,强制各个事务串行执行。
3.2 死锁
两个或多个事务在统一资源上相互占用,并请求对方占用的资源,从而导致恶性循环的问题。多个事务试图以不同顺序锁定资源时、多个事务同时锁定同一个资源就会产生死锁。InnoDB目前处理死锁的方法是将持有最少行级锁的事务进行回滚。
3.3 事务日志
使用事务日志,存储引擎在修改表的数据时只需要修改内存拷贝,再把该修改行为持久化在硬盘的事务日志中。同时写事务日志时磁盘一小块区域的顺序IO,速度极快。事务日志持久化后,内存中被修改的数据由后台程序慢慢刷回磁盘。
如果数据修改以及记录到事务日志并持久化,此时系统崩溃,存储引擎可以在系统重启之后自动恢复数据。
3.4 MySQL的事务
MySQL默认采用自动提交事务。如果不是显式的生命一个事务,MySQL会把每一个查询都当作一个事务来操作。MySQL核心服务层部管理事务,由下层的存储引擎来实现,因此一个事务中使用多种存储引擎不可靠的。
3.5 隐式和显示锁定
InnoDB是两阶段锁定协议,在事务执行过程中,随时都可以执行锁定,锁只有在执行commit或者rollback时才会释放,并且所有的锁都在一瞬间释放。
4. 多版本并发控制(MVCC)
可以认为MVCC是行级锁的一个变种,很多情况下避免了加锁,基本实现了非阻塞读。典型的有乐观并发控制和悲观病啊控制。
MVCC是通过保存某个时间点的快照来实现的,就是说不管执行多久,每个事务看到的数据是一致的。根据事务开始时间不同, 每个事务对同一张表,同一时刻看到的数据可能是不一样的。
4.1 InnoDB的实现
InnoDB的MVCC是通过在每一行记录的后面保存两个隐藏列来实现。一个列保存了行的创建时间,一个是保存了过期时间(删除时间),当然存储的不是实际的时间,而是系统版本号(system version number),每开始一个事务,版本号都会自动递增。事务开始时刻的系统版本号作为事务的版本号,用来和查询到的每行记录的版本号作比较。
- Select:InnoDB会根据这两个条件来查询:
- 只查找版本号小于或者等于当前事务的数据行,这样可以保证事务读取到的数据要么是在事务开始前就存在的,要么是自己插入或者修改的。
- 行的删除要么未定义,要么大于当前事务的版本号,这样可以保证读取到的数据在事务开始之前没有被删除
- Insert:InnoDB为新插入的每一行数据保存当前的系统版本号为行版本号。
- Delete:InnoDB为删除的每一行保存当前的版本号为行删除标识。
- Update:InnoDB为插入一条新纪录,保存当前系统版本号为行版本号,同时保存当前系统的版本号到原来的行为行删除标识。
5.MySQL的存储引擎
InnoDB采用MVCC支持高并发,默认的隔离级别是Repetable read,通过间隙锁来防止幻读。同时InnoDB是基于聚簇索引建立的。具体的内容阅读到后面章节再细写。
- 原文作者:阿林
- 原文链接:https://itachi.xyz/post/high-performance-mysql-1.html
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。