MySQL-存储引擎

文章目录

    • 1. MySQL的体系结构
    • 2. 存储引擎
      • 2.1 存储引擎概述
      • 2.2 存储引擎的类型及选择方案
      • 2.3 操作存储引擎
      • 2.4 InnoDB存储引擎
        • 2.4.1 逻辑存储结构
        • 2.4.2 架构
          • 2.4.2.1 内存结构
          • 2.4.2.2 磁盘结构
          • 2.4.2.3 后台线程
        • 2.4.3 事务
          • 2.4.3.1 Undo Log(原子性)
          • 2.4.3.2 Redo Log(持久性)
        • 2.4.4 MVCC(脏读和不可重复读)
          • 2.4.4.1 当前读和快照读
          • 2.4.4.2 三个隐式字段
          • 2.4.4.3 Undo Log
          • 2.4.4.4 ReadView

1. MySQL的体系结构

  • MySQL 由连接池、 SQL 接口、解析器、优化器、缓存、存储引擎等组成,可以分为三层,即 MySQL Server 层、存储引擎层和文系
    统层。 MySQL Server 层又包括连接层和 SQL 层。Connectors 不属于以上任何一层,可以将 Connectors 理解为各种客户端、应用服务,主要指的是不同语言与 SQL 的交互。 如下是官方文档中 MySQL 的基础架构图:

    MySQL-存储引擎_第1张图片

  1. MySQL Server层

    1. Connection Pool(连接池): 最上层是一些客户端和连接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限

    2. SQL 层: MySQL 的核心, MySQL 的核心服务都是在这层实现的。主要包含权限判断查询缓存解析器预处理查询优化器缓存执行计划

      1. 权限判断可以审核用户有没有访问某个库、某个表,或者表里某行数据的权限。
      2. 查询缓存通过 Query Cache 进行操作,如果数据在 Query Cache 中,则直接返回结果给客户端,不必再进行查询解析、优化和执行 等过程。
      3. 查询解析器针对 SQL 语句进行解析,判断语法是否正确。
      4. 预处理器对解析器无法解析的语义进行处理。
      5. 查询优化器对 SQL 进行改写和相应的优化,并生成最优的执行计划,就可以调用程序的 API 接口,通过存储引擎层访问数据。
      名称 说明
      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 缓存、权限缓存等。

  2. 存储引擎层 :存储引擎层是 MySQL 数据库区别于其他数据库最核心的一点,也是 MySQL 最具特色的一个地方。主要负责MySQL中数据的存储和提取,此外,数据库中的索引是在存储引擎层实现的。因为在关系数据库中,数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和操作此表的类型)。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。

  3. 文件系统层 :主要是将数据(如: redolog、undolog、数据、索引、二进制日志、错误日志、查询日志、慢查询日志等)存储在文件系统之上,并完成与存储引擎的交互。

2. 存储引擎

2.1 存储引擎概述

  1. 定义:数据库存储引擎是数据库底层软件组件,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据操作简而言之,存储引擎就是指表的类型。数据库的存储引擎决定了表在计算机中的存储方式。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎还可以获得特定的功能。
  2. MySQL 提供了多个不同的存储引擎,包括处理事务安全表的引擎和处理非事务安全表的引擎。在 MySQL 中,不需要在整个服务器中使用同一种存储引擎,针对具体的要求,可以对每一个表使用不同的存储引擎。

2.2 存储引擎的类型及选择方案

MySQL-存储引擎_第2张图片

MySQL 存储引擎特性汇总和对比
特性 MyISAM InnoDB MEMORY
存储限制 支持
事务安全 不支持 支持 不支持
锁机制 表锁 行锁 表锁
B 树索引 支持 支持 支持
哈希索引 不支持 不支持 支持
全文索引 支持 不支持 不支持
集群索引 不支持 支持 不支持
数据缓存 支持 支持
索引缓存 支持 支持 支持
数据可压缩 支持 不支持 不支持
空间使用 N/A
内存使用 中等
批量插入速度
支持外键 不支持 支持 不支持

  1. MyISAM的使用场景:

    1. 在 MySQL 5.1 版本及之前的版本, MyISAM 是默认的存储引擎
    2. MyISAM 存储引擎不支持事务和外键,所以访问速度比较快。如果应用主要以读取和写入为主,只有少量的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择 MyISAM 存储引擎是非常适合的。
  2. InnoDB的使用场景:

    1. MySQL 5.5 版本之后默认的事务型引擎修改为 InnoDB
    2. 如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询以外,还包括很多的更新、删除操作,那么 InnoDB 存储引擎是比较合适的选择。
  3. Memory的使用场景:

    1. MEMORY 存储引擎将所有数据保存在 RAM 中,所以该存储引擎的数据访问速度快,但是安全上没有保障。

    2. 将所有数据保存在内存中,访问速度快,通常用于临时表及缓存。MEMORY的缺陷就是
      对表的大小有限制,太大的表无法缓存在内存中,而且无法保障数据的安全性。

2.3 操作存储引擎

  1. 查看数据库所支持的引擎类型 :

    SHOW ENGINES
    

    MySQL-存储引擎_第3张图片

  2. 查看数据库默认存储引擎:

    SHOW VARIABLES LIKE 'default_storage_engine%';
    
  3. 修改数据库临时的默认存储引擎 :

    SET default_storage_engine=< 存储引擎名 >
    
  4. 建表时指定存储引擎 :

    CREATE TABLE 表名(
    字段1 字段1类型 [ COMMENT 字段1注释 ] ,
    ......
    字段n 字段n类型 [COMMENT 字段n注释 ]
    ) ENGINE = INNODB [ COMMENT 表注释 ] ;
    
  5. 修改表的存储引擎:

    ALTER TABLE <表名> ENGINE=<存储引擎名>;
    

2.4 InnoDB存储引擎

2.4.1 逻辑存储结构
  • InnoDB的逻辑存储结构如下图所示:

    MySQL-存储引擎_第4张图片

  1. 表空间(Tablespace):表空间是InnoDB存储引擎逻辑结构的最高层, 如果用户启用了参数 innodb_file_per_table(在8.0版本中默认开启) ,则每张表都会有一个表空间(xxx.ibd),一个mysql实例可以对应多个表空间,用于存储记录、索引等数据。

  2. 段(Segment):分为数据段(Leaf node segment)、索引段(Non-leaf node segment)、回滚段(Rollback segment),InnoDB是索引组织表,数据段就是B+树的叶子节点, 索引段即为B+树的非叶子节点。段用来管理多个Extent(区)。

  3. 区 (Extent):表空间的单元结构,每个区的大小为1M。 默认情况下, InnoDB存储引擎页大小为16K, 即一个区中一共有64个连续的页

  4. 页(Page):是InnoDB 存储引擎磁盘管理的最小单元,每个页的大小默认为 16KB。为了保证页的连续性InnoDB 存储引擎每次从磁盘申请 4-5 个区

  5. 行(Row):InnoDB 存储引擎数据是按行进行存放的。在行中,默认有两个隐藏字段:
    Trx_id:每次对某条记录进行改动时,都会把对应的事务id赋值给trx_id隐藏列。
    Roll_pointer:每次对某条引记录进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针**,可以通过它来找到该记录修改前的信息**。

2.4.2 架构
  • 下面是InnoDB架构图,左侧为内存结构,右侧为磁盘结构。

    MySQL-存储引擎_第5张图片

2.4.2.1 内存结构
  • 在左侧的内存结构中,主要分为这么四大块儿: Buffer PoolChange BufferAdaptive Hash IndexLog Buffer
  1. Buffer Pool

    • InnoDB存储引擎基于磁盘文件存储,访问物理硬盘和在内存中进行访问,速度相差很大,为了尽可能弥补这两者之间的I/O效率的差值,就需要把经常使用的数据加载到缓冲池中,避免每次访问都进行磁盘I/O。在InnoDB的缓冲池中不仅缓存了索引页和数据页,还包含了undo页、插入缓存、自适应哈希索引以及InnoDB的锁信息等等。
    • 缓冲池 Buffer Pool,是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度。
    • 缓冲池以Page页为单位,底层采用链表数据结构管理Page。根据状态,将Page分为三种类型:
      • free page:空闲page,未被使用。
      • clean page:被使用page,数据没有被修改过。
      • dirty page:脏页,被使用page,数据被修改过,也中数据与磁盘的数据产生了不一致。
  2. Change Buffer:

    • Change Buffer,更改缓冲区(针对于非唯一二级索引页),在执行DML语句时,如果这些数据Page没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在更改缓冲区 Change Buffer中,在未来数据被读取时,再将数据合并恢复到Buffer Pool中,再将合并后的数据刷新到磁盘中。
  3. Adaptive Hash Index:

    • 自适应hash索引,用于优化对Buffer Pool数据的查询。MySQL的innoDB引擎中虽然没有直接支持hash索引,但是给我们提供了一个功能就是这个自适应hash索引。因为前面我们讲到过,hash索引在进行等值匹配时,一般性能是要高于B+树的,因为hash索引一般只需要一次IO即可,而B+树,可能需要几次匹配,所以hash索引的效率要高,但是hash索引又不适合做范围查询、模糊匹配等。InnoDB存储引擎会监控对表上各索引页的查询,如果观察到在特定的条件下hash索引可以提升速度,则建立hash索引,称之为自适应hash索引。
  4. Log Buffer:

    • Log Buffer:日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log 、undo log),默认大小为 16MB,日志缓冲区的日志会定期刷新到磁盘中。如果需要更新、插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘 I/O。

    • 参数:

      1. innodb_log_buffer_size:缓冲区大小

      2. innodb_flush_log_at_trx_commit:日志刷新到磁盘时机,取值主要包含以下三个:

        取值 作用
        1 日志在每次事务提交时写入并刷新到磁盘,默认值
        0 每秒将日志写入并刷新到磁盘一次
        2: 日志在每次事务提交后写入,并每秒刷新到磁盘一次
2.4.2.2 磁盘结构
  1. System Tablespace:系统表空间是更改缓冲区的存储区域。如果表是在系统表空间而不是每个表文件或通用表空间中创建的,它也可能包含表和索引数据。(在MySQL5.x版本中还包含InnoDB数据字典、undolog等)。

    MySQL-存储引擎_第6张图片

  2. File-Per-Table Tablespaces:如果开启了innodb_file_per_table开关 ,则每个表的文件表空间包含单个InnoDB表的数据和索
    引 ,并存储在文件系统上的单个数据文件中。

    MySQL-存储引擎_第7张图片

  3. General Tablespaces:通用表空间,需要通过 CREATE TABLESPACE 语法创建通用表空间,在创建表时,可以指定该表空间。

    MySQL-存储引擎_第8张图片

  4. Undo Tablespaces:撤销表空间,MySQL实例在初始化时会自动创建两个默认的undo表空间(初始大小16M),用于存储undo log日志。

  5. Temporary Tablespaces:InnoDB 使用会话临时表空间和全局临时表空间。存储用户创建的临时表等数据。

  6. Doublewrite Buffer Files :双写缓冲区,innoDB引擎将数据页从Buffer Pool刷新到磁盘前,先将数据页写入双写缓冲区文件
    中,便于系统异常时恢复数据。

    在这里插入图片描述

  7. Redo Log:重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中, 用于在刷新脏页到磁盘时,发生错误时, 进行数据恢复使用。以循环方式写入重做日志文件,涉及两个文件:

    在这里插入图片描述

2.4.2.3 后台线程
  • 在InnoDB的后台线程中,分为4类,分别是:Master ThreadIO ThreadPurge ThreadPage Cleaner Thread
  1. Master Thread:核心后台线程,负责调度其他线程,还负责将缓冲池中的数据异步刷新到磁盘中, 保持数据的一致性,还包括脏页的刷新、合并插入缓存、undo页的回收。

  2. IO Thread:在InnoDB存储引擎中大量使用了AIO来处理IO请求, 这样可以极大地提高数据库的性能,而IO Thread主要负责这些IO请求的回调。

    线程类型 默认个数 职责
    Read thread 4 负责读操作
    Write thread 4 负责写操作
    Log thread 1 负责将日志缓冲区刷新到磁盘
    Insert buffer thread 1 负责将写缓冲区内容刷新到磁盘
  3. Purge Thread:主要用于回收事务已经提交了的undo log,在事务提交之后,undo log可能不用了,就用它来回收。

  4. Page Cleaner Thread:协助 Master Thread 刷新脏页到磁盘的线程,它可以减轻 Master Thread 的工作压力,减少阻塞。

2.4.3 事务
  • 实际上,我们研究事务的原理,就是研究MySQL的InnoDB引擎是如何保证事务的这四大特性。而对于这四大特性,实际上分为两个部分。 其中的原子性、一致性、持久化,实际上是由InnoDB中的两份日志来保证的,一份是redo log日志,一份是undo log日志。 而隔离性是通过数据库的锁,加上MVCC来保证的。

    MySQL-存储引擎_第9张图片

2.4.3.1 Undo Log(原子性)
  • 定义:回滚日志,用于记录数据被修改前的信息 , 作用包含两个 : 提供回滚(保证事务的原子性) 和MVCC(多版本并发控制)

  • 原理:undo log和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。

  • 分类

    1. Undo log销毁:undo log在事务执行时产生,事务提交时,并不会立即删除undo log,因为这些日志可能还用于MVCC。
    2. Undo log存储:undo log采用段的方式进行管理和记录,存放在前面介绍的 rollback segment回滚段中,内部包含1024个undo log segment。
2.4.3.2 Redo Log(持久性)
  • 定义:重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo logfile),前者是在内存中后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中, 用于在刷新脏页到磁盘,发生错误时, 进行数据恢复使用。

  • 原理:有了redolog之后,当对缓冲区的数据进行增删改之后,会首先将操作的数据页的变化,记录在redo log buffer中。在事务提交时,会将redo log buffer中的数据刷新到redo log磁盘文件中。过一段时间之后,如果刷新缓冲区的脏页到磁盘时,发生错误,此时就可以借助于redo log进行数据恢复,这样就保证了事务的持久性。 而如果脏页成功刷新到磁盘 或 或者涉及到的数据已经落盘,此时redolog就没有作用了,就可以删除了,所以存在的两个redolog文件是循环写的。

    MySQL-存储引擎_第10张图片

2.4.4 MVCC(脏读和不可重复读)
2.4.4.1 当前读和快照读
  • 当前读读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select … lock in share mode(共享锁),select …for update、update、insert、delete(排他锁)都是一种当前读。
  • 快照读:简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读
    1. Read Committed:每次select,都生成一个快照读
    2. Repeatable Read:开启事务后第一个select语句才是快照读的地方
    3. Serializable:快照读会退化为当前读
  • MVCC:全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段undo log日志readView
2.4.4.2 三个隐式字段
  • 实际上除了这三个字段以外,InnoDB还会自动的给我们添加三个隐藏字段及其含义分别是:

    隐藏字段 含义
    DB_TRX_ID 最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。
    DB_ROLL_PTR 回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本。
    DB_ROW_ID 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。
2.4.4.3 Undo Log
  • 回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即
    被删除

  • 最终我们发现,不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表链表的头部是最新的旧记录,链表尾部是最早的旧记录

    MySQL-存储引擎_第11张图片

2.4.4.4 ReadView
  • 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

你可能感兴趣的:(MySQL,mysql,数据库)