赞
踩
MySQL 由连接池、 SQL 接口、解析器、优化器、缓存、存储引擎等组成,可以分为三层,即 MySQL Server 层、存储引擎层和文系
统层。 MySQL Server 层又包括连接层和 SQL 层。Connectors 不属于以上任何一层,可以将 Connectors 理解为各种客户端、应用服务,主要指的是不同语言与 SQL 的交互。 如下是官方文档中 MySQL 的基础架构图:
MySQL Server层:
Connection Pool(连接池): 最上层是一些客户端和连接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
SQL 层: MySQL 的核心, MySQL 的核心服务都是在这层实现的。主要包含权限判断、查询缓存、解析器、预处理、查询优化器、缓存和执行计划。
名称 | 说明 |
---|---|
Management Services & Utilities | MySQL 的系统管理和控制工具,包括备份恢复、 MySQL 复制、集群等。 |
SQL Interface( SQL 接口) | 用来接收用户的 SQL 命令,返回用户需要查询的结果。例如 SELECT FROM 就是调用 SQL Interface。 |
Parser(查询解析 器) | 在 SQL 命令传递到解析器的时候会被解析器验证和解析,以便 MySQL 优化器可以识别的数据结构或返回 SQL 语句的错误。 |
Optimizer(查询优 化器) | SQL 语句在查询之前会使用查询优化器对查询进行优化,同时验证用户是否有权限进行查询,缓存中是否有可 用的最新数据。它使用“选取-投影-连接”策略进行查询。 例如 SELECT id, name FROM student WHERE gender = “女”;语句中, SELECT 查询先根据 WHERE 语句进 行选取, 而不是将表全部查询出来以后再进行 gender 过滤。 SELECT 查询先根据 id 和 name 进行属性投影, 而不是将属性全部取出以后再进行过滤,将这两个查询条件连接起来生成最终查询结果。 |
Caches & Buffers (查询缓存) | 如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。这个缓存机制是由一系列小缓存组 成的,比如表缓存、记录缓存、 key 缓存、权限缓存等。 |
存储引擎层 :存储引擎层是 MySQL 数据库区别于其他数据库最核心的一点,也是 MySQL 最具特色的一个地方。主要负责MySQL中数据的存储和提取,此外,数据库中的索引是在存储引擎层实现的。因为在关系数据库中,数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和操作此表的类型)。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。
文件系统层 :主要是将数据(如: redolog、undolog、数据、索引、二进制日志、错误日志、查询日志、慢查询日志等)存储在文件系统之上,并完成与存储引擎的交互。
MySQL 存储引擎特性汇总和对比 | |||
---|---|---|---|
特性 | MyISAM | InnoDB | MEMORY |
存储限制 | 有 | 支持 | 有 |
事务安全 | 不支持 | 支持 | 不支持 |
锁机制 | 表锁 | 行锁 | 表锁 |
B 树索引 | 支持 | 支持 | 支持 |
哈希索引 | 不支持 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 | 不支持 |
集群索引 | 不支持 | 支持 | 不支持 |
数据缓存 | 支持 | 支持 | |
索引缓存 | 支持 | 支持 | 支持 |
数据可压缩 | 支持 | 不支持 | 不支持 |
空间使用 | 低 | 高 | N/A |
内存使用 | 低 | 高 | 中等 |
批量插入速度 | 高 | 低 | 高 |
支持外键 | 不支持 | 支持 | 不支持 |
MyISAM的使用场景:
InnoDB的使用场景:
Memory的使用场景:
MEMORY 存储引擎将所有数据保存在 RAM 中,所以该存储引擎的数据访问速度快,但是安全上没有保障。
将所有数据保存在内存中,访问速度快,通常用于临时表及缓存。MEMORY的缺陷就是
对表的大小有限制,太大的表无法缓存在内存中,而且无法保障数据的安全性。
查看数据库所支持的引擎类型 :
SHOW ENGINES
查看数据库默认存储引擎:
SHOW VARIABLES LIKE 'default_storage_engine%';
修改数据库临时的默认存储引擎 :
SET default_storage_engine=< 存储引擎名 >
建表时指定存储引擎 :
CREATE TABLE 表名(
字段1 字段1类型 [ COMMENT 字段1注释 ] ,
......
字段n 字段n类型 [COMMENT 字段n注释 ]
) ENGINE = INNODB [ COMMENT 表注释 ] ;
修改表的存储引擎:
ALTER TABLE <表名> ENGINE=<存储引擎名>;
InnoDB的逻辑存储结构如下图所示:
表空间(Tablespace):表空间是InnoDB存储引擎逻辑结构的最高层, 如果用户启用了参数 innodb_file_per_table(在8.0版本中默认开启) ,则每张表都会有一个表空间(xxx.ibd),一个mysql实例可以对应多个表空间,用于存储记录、索引等数据。
段(Segment):分为数据段(Leaf node segment)、索引段(Non-leaf node segment)、回滚段(Rollback segment),InnoDB是索引组织表,数据段就是B+树的叶子节点, 索引段即为B+树的非叶子节点。段用来管理多个Extent(区)。
区 (Extent):表空间的单元结构,每个区的大小为1M。 默认情况下, InnoDB存储引擎页大小为16K, 即一个区中一共有64个连续的页。
页(Page):是InnoDB 存储引擎磁盘管理的最小单元,每个页的大小默认为 16KB。为了保证页的连续性,InnoDB 存储引擎每次从磁盘申请 4-5 个区。
行(Row):InnoDB 存储引擎数据是按行进行存放的。在行中,默认有两个隐藏字段:
Trx_id:每次对某条记录进行改动时,都会把对应的事务id赋值给trx_id隐藏列。
Roll_pointer:每次对某条引记录进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针**,可以通过它来找到该记录修改前的信息**。
下面是InnoDB架构图,左侧为内存结构,右侧为磁盘结构。
Buffer Pool
、Change Buffer
、Adaptive Hash Index
、Log Buffer
。Buffer Pool:
Change Buffer:
Adaptive Hash Index:
Log Buffer:
Log Buffer:日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log 、undo log),默认大小为 16MB,日志缓冲区的日志会定期刷新到磁盘中。如果需要更新、插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘 I/O。
参数:
innodb_log_buffer_size:缓冲区大小
innodb_flush_log_at_trx_commit:日志刷新到磁盘时机,取值主要包含以下三个:
取值 | 作用 |
---|---|
1 | 日志在每次事务提交时写入并刷新到磁盘,默认值 |
0 | 每秒将日志写入并刷新到磁盘一次 |
2: | 日志在每次事务提交后写入,并每秒刷新到磁盘一次 |
System Tablespace:系统表空间是更改缓冲区的存储区域。如果表是在系统表空间而不是每个表文件或通用表空间中创建的,它也可能包含表和索引数据。(在MySQL5.x版本中还包含InnoDB数据字典、undolog等)。
File-Per-Table Tablespaces:如果开启了innodb_file_per_table开关 ,则每个表的文件表空间包含单个InnoDB表的数据和索
引 ,并存储在文件系统上的单个数据文件中。
General Tablespaces:通用表空间,需要通过 CREATE TABLESPACE 语法创建通用表空间,在创建表时,可以指定该表空间。
Undo Tablespaces:撤销表空间,MySQL实例在初始化时会自动创建两个默认的undo表空间(初始大小16M),用于存储undo log日志。
Temporary Tablespaces:InnoDB 使用会话临时表空间和全局临时表空间。存储用户创建的临时表等数据。
Doublewrite Buffer Files :双写缓冲区,innoDB引擎将数据页从Buffer Pool刷新到磁盘前,先将数据页写入双写缓冲区文件
中,便于系统异常时恢复数据。
Redo Log:重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中, 用于在刷新脏页到磁盘时,发生错误时, 进行数据恢复使用。以循环方式写入重做日志文件,涉及两个文件:
Master Thread
、IO Thread
、Purge Thread
、Page Cleaner Thread
。Master Thread:核心后台线程,负责调度其他线程,还负责将缓冲池中的数据异步刷新到磁盘中, 保持数据的一致性,还包括脏页的刷新、合并插入缓存、undo页的回收。
IO Thread:在InnoDB存储引擎中大量使用了AIO来处理IO请求, 这样可以极大地提高数据库的性能,而IO Thread主要负责这些IO请求的回调。
线程类型 | 默认个数 | 职责 |
---|---|---|
Read thread | 4 | 负责读操作 |
Write thread | 4 | 负责写操作 |
Log thread | 1 | 负责将日志缓冲区刷新到磁盘 |
Insert buffer thread | 1 | 负责将写缓冲区内容刷新到磁盘 |
Purge Thread:主要用于回收事务已经提交了的undo log,在事务提交之后,undo log可能不用了,就用它来回收。
Page Cleaner Thread:协助 Master Thread 刷新脏页到磁盘的线程,它可以减轻 Master Thread 的工作压力,减少阻塞。
实际上,我们研究事务的原理,就是研究MySQL的InnoDB引擎是如何保证事务的这四大特性。而对于这四大特性,实际上分为两个部分。 其中的原子性、一致性、持久化,实际上是由InnoDB中的两份日志来保证的,一份是redo log日志,一份是undo log日志。 而隔离性是通过数据库的锁,加上MVCC来保证的。
定义:回滚日志,用于记录数据被修改前的信息 , 作用包含两个 : 提供回滚(保证事务的原子性) 和MVCC(多版本并发控制) 。
原理:undo log和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。
分类:
定义:重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo logfile),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中, 用于在刷新脏页到磁盘,发生错误时, 进行数据恢复使用。
原理:有了redolog之后,当对缓冲区的数据进行增删改之后,会首先将操作的数据页的变化,记录在redo log buffer中。在事务提交时,会将redo log buffer中的数据刷新到redo log磁盘文件中。过一段时间之后,如果刷新缓冲区的脏页到磁盘时,发生错误,此时就可以借助于redo log进行数据恢复,这样就保证了事务的持久性。 而如果脏页成功刷新到磁盘 或 或者涉及到的数据已经落盘,此时redolog就没有作用了,就可以删除了,所以存在的两个redolog文件是循环写的。
实际上除了这三个字段以外,InnoDB还会自动的给我们添加三个隐藏字段及其含义分别是:
隐藏字段 | 含义 |
---|---|
DB_TRX_ID | 最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。 |
DB_ROLL_PTR | 回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本。 |
DB_ROW_ID | 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。 |
回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即
被删除。
最终我们发现,不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。ReadView中包含了四个核心字段:
字段 | 含义 |
---|---|
m_ids | 当前活跃的事务ID集合 |
min_trx_id | 最小活跃事务ID |
max_trx_id | 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的) |
creator_trx_id | ReadView创建者的事务ID |
而在readview中就规定了版本链数据的访问规则:trx_id 代表当前undolog版本链对应事务ID。
条件 | 是否可以访问 | 说明 |
---|---|---|
trx_id == creator_trx_id | 可以访问该版本 | 成立,说明数据是当前这个事务更改的。 |
trx_id < min_trx_id | 可以访问该版本 | 成立,说明数据已经提交了。 |
trx_id > max_trx_id | 不可以访问该版本 | 成立,说明该事务是在 ReadView生成后才开启。 |
min_trx_id <= trx_id <= max_trx_id | 如果trx_id不在m_ids中, 是可以访问该版本的 | 成立,说明数据已经提交。 |
不同的隔离级别,生成ReadView的时机不同:
READ COMMITTED :在事务中每一次执行快照读时生成ReadView。
REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。