提起MySQL,其实网上已经有一大把教程了,为什么我还要写这篇文章呢,大概是因为网上很多网站都是比较零散,而且描述不够直观,不能系统对MySQL相关知识有一个系统的学习,导致不能形成知识体系。为此我撰写了这篇文章,试图让这些底层架构相关知识更加直观易懂:

  • 尽量以图文的方式描述技术原理;
  • 涉及到关键的技术,附加官网或者技术书籍来源,方便大家进一步扩展学习;
  • 涉及到的背景知识尽可能做一个交代,比如讨论到log buffer的刷盘方式,延伸一下IO写磁盘相关知识点。

好了,MySQL从不会到精通系列马上就要开始了(看完之后还是不会的话…请忽略这句话)。

img

可能会有同学问:为啥不直接学更加先进的TiDB,或者是强大的OceanBase。

其实,MySQL作为老牌的应用场景广泛的关系型开源数据库,其底层架构是很值得我们学习的,吸收其设计精华,那么我们在平时的方案设计工作中也可以借鉴,如果项目中用的是MySQL,那么就能够把数据库用的更好了,了解了MySQL底层的执行原理,对于调优工作也是有莫大帮助的。本文我重点讲述MySQL底层架构,涉及到:

  • 内存结构buffer poollog bufferchange buffer,buffer pool的页淘汰机制是怎样的;
  • 磁盘结构系统表空间独立表空间通用表空间undo表空间redo log
  • 以及IO相关底层原理、查询SQL执行流程、数据页结构行结构描述、聚集索引辅助索引的底层数据组织方式、MVCC多版本并发控制的底层实现原理,以及可重复读读已提交是怎么通过MVCC实现的。

image-20200530231121252

看完文本文,您将了解到:

  1. **整体架构:**InnoDB存储架构是怎样的 (1、MySQL架构)
  2. **工作原理:**查询语句的底层执行流程是怎样的 (2、查询SQL执行流程)
  3. **IO性能:**文件IO操作写磁盘有哪几种方式,有什么IO优化方式 (3.1.2、关于磁盘IO的方式)
  4. 缓存:InnoDB缓存(buffer pool, log buffer)的刷新方式有哪些(3.1.2.2、innodb_flush_method)
  5. **缓存:**log buffer是在什么时候写入到磁盘的(3.10.2、如何保证数据不丢失 - 其中第四步log buffer持久化到磁盘的时机为)
  6. **缓存:**为什么redo log prepare状态也要写磁盘?(3.10.2、如何保证数据不丢失 - 为什么第二步redo log prepare状态也要写磁盘?)
  7. **缓存:**脏页写盘一般发生在什么时候(3.10.2、如何保证数据不丢失 - 其中第五步:脏页刷新到磁盘的时机为)
  8. **缓存:**为什么唯一索引的更新不可以借助change buffer(3.2、Change Buffer)
  9. 缓存:log buffer的日志刷盘控制参数innodb_flush_log_at_trx_commit对写性能有什么影响(3.4.1、配置参数)
  10. **缓存:**buffer pool的LRU是如何实现的,为什么要这样实现(3.1.1、缓冲池LRU算法)
  11. **表存储:**系统表空间的结构,MySQL InnoDB磁盘存储格式,各种表空间(系统表空间,独立表空间,通用表空间)的作用和优缺点是什么,ibdataibdfrm文件分别是干嘛的(3.5、表空间)
  12. **行字段存储:**底层页和行的存储格式(3.6、InnoDB底层逻辑存储结构)
  13. 行字段存储:varcharnull底层是如何存储的,最大可用存储多大的长度(3.6.3.1、MySQL中varchar最大长度是多少)
  14. **行字段存储:**行记录太长了,一页存不下,该怎么存储?(3.6.3.2、行记录超过页大小如何存储)
  15. **索引:**数据库索引的组织方式是怎样的,明白为什么要采用B+树,而不是哈希表、二叉树或者B树(3.7、索引 - 为什么MySQL使用B+树)
  16. **索引:**索引组织方式是怎样的,为什么大字段会影响表性能(查询性能,更新性能)(3.7、索引)
  17. 索引:覆盖索引联合索引什么情况下会生效(3.7.2、辅助索引)
  18. **索引:**什么是索引下推,索引下推减少了哪方面的开销?(3.7.2、辅助索引 - 索引条件下推)
  19. 索引:Change Buffer对二级索引DML语句有什么优化(3.2、Change Buffer)
  20. **数据完整性:**MySQL是如何保证数据完整性的,redo logundo logbuffer pool数据完整性的关键作用分别是什么(3.10.2、如何保证数据不丢失)
  21. MVCC:MVCC底层是怎么实现的,可重复读和读已提交是怎么实现的(3.11.2、MVCC实现原理)
  22. 双写缓冲区有什么作用(3.9、Doublewrite Buffer)
  23. Redo Log在一个事务中是在什么时候写入的?binlog和Redo Log有什么区别?(3.10.1、Redo Log在事务中的写入时机)

1、MySQL架构

如下图为MySQL架构涉及到的常用组件:

image-20200517155127246

2、查询SQL执行流程

有如下表格:

image-20200517183833415

我们执行以下sql:

select * from t_user where user_id=10000;

2.1、MySQL客户端与服务器建立连接

如下图,建立过程:

  • 客户端通过mysql命令发起连接请求;
  • 经过三次握手后与服务端建立TCP连接;
  • 连接器接收到请求之后使用用户密码进行身份验证;
  • 验证通过之后,获取用户的权限信息缓存起来,该连接后面都是基于该缓存中的权限执行sql

image-20200517194803475

对于Java应用程序来说,一般会把建立好的连接放入数据库连接池中进行复用,只要这个连接不关闭,就会一直在MySQL服务端保持着,可以通过show processlist命令查看,如下:

image-20200517185119239

注意,这里有个Time,表示这个连接多久没有动静了,上面例子是656秒没有动静,默认地,如果超过8个小时还没有动静,连接器就会自动断开连接,可以通过wait_timeout参数进行控制。

2.2、执行SQL

如下图,执行sql:

image-20200517231413373

  • 服务端接收到客户端的查询sql之后,先尝试从查询缓存中查询该sql是否已经有缓存的结果了,如果有则直接返回结果,如果没有则执行下一步;
  • 分析器拿到sql之后会尝试对sql语句进行词法分析和语法分析,校验语法的正确性,通过之后继续往下执行;
  • 优化器拿到分析器的sql之后,开始继续解析sql,判断到需要走什么索引,根据实际情况重写sql,最终生成执行计划;
  • 执行器根据执行计划执行sql,执行之前会先进行操作权限校验;然后根据表存储引擎调用对饮接口进行查询数据,这里的扫描行数就是指的接口返回的记录数,执行器拿到返回记录之后进一步加工,如本例子:
    • 执行器拿到select * from t_user where user_id=10000的所有记录,在依次判断user_name是不是等于"arthinking",获取到匹配的记录。

3、InnoDB引擎架构

如下图,为存储引擎的架构:

image-20200530224136957

其实内存中的结构不太好直接观察到,不过磁盘的还是可以看到的,我们找到磁盘中MySQL的数据文件夹看看:

cd innodb_data_home_dir 查看MySQL 数据目录:

|- ib_buffer_pool  // 保存缓冲池中页面的表空间ID和页面ID,用于重启恢复缓冲池
|- ib_logfile0  // redo log 磁盘文件1
|- ib_logfile1  // redo log 磁盘文件2,默认情况下,重做日志存在磁盘的这两个文件中,循环的方式写入重做日志
|- ibdata1  // 系统表空间文件
|- ibtmp1  // 默认临时表空间文件,可通过innodb_temp_data_file_path属性指定文件位置
|- mysql/
|- mysql-bin.000001  // bin log文件
|- mysql-bin.000001  // bin log文件
...
|- mysql-bin.index  // bin log文件索引
|- mysqld.local.err  // 错误日志
|- mysqld.local.pid  // mysql进程号
|- performance_schema/  // performance_schema数据库
|- sys/  // sys数据库
|- test/  // 数据库文件夹|- db.opt  // test数据库配置文件,包含数据库字符集属性|- t.frm  // 数据表元数据文件,不管是使用独立表空间还是系统表空间,每个表都对应有一个|- t.ibd  // 数据库表独立表空间文件,如果使用的是独立表空间,则一个表对应一个ibd文件,否则保存在系统表空间文件中

innodb_data_home_dir1

ib_buffer_pool2

ib_logfile03

ibtmp14

db.opt5

接下来我们逐一来介绍。

3.1、buffer pool

image-20200530224418964

buffer pool缓冲池)是主内存中的一个区域,在InnoDB访问表数据索引数据的时候,会顺便把对应的数据页缓存到缓冲池中。如果直接从缓冲池中直接读取数据将会加快处理速度。在专用服务器上,通常将80%左右的物理内存分配给缓冲池。

为了提高缓存管理效率,缓冲池把页面链接为列表,使用改进版的LRU算法将很少使用的数据从缓存中老化淘汰掉。

3.1.1、缓冲池LRU算法

通过使用改进版的LRU算法来管理缓冲池列表。

当需要把新页面存储到缓冲池中的时候,将淘汰最近最少使用的页面,并将新页面添加到旧子列表的头部。

image-20200519225450188

该算法运行方式:

  • 默认 3/8缓冲池用于旧子列表;
  • 当新页面如缓冲池时,首先将其插入旧子列表头部
  • 重复访问旧子列表的页面,将使其移动至新子列表的头部;
  • 随着数据库的运行,页面逐步移至列表尾部,缓冲池中未被方位的页面最终将被老化淘汰。

相关优化参数:

  • innodb_old_blocks_pct:控制LRU列表中旧子列表的百分比,默认是37,也就是3/8,可选范围为5~95;
  • innodb_old_blocks_time :指定第一次访问页面后的时间窗口,该时间窗口内访问页面不会使其移动到LRU列表的最前面。默认是1000,也就是1秒。

innodb_old_blocks_time很重要,有了这1秒,对于全表扫描,由于是顺序扫描的,一般同一个数据页的数据都是在一秒内访问完成的,不会升级到新子列表中,一直在旧子列表淘汰数据,所以不会影响到新子列表的缓存。

3.1.2、关于磁盘IO的方式

image-20200530224453194

O_DIRECTinnodb_flush_method参数的一个可选值。

这里先介绍下和数据库性能密切相关的文件IO操作方法

3.1.2.1、文件IO操作方法

数据库系统是基于文件系统的,其性能和设备读写的机制有密切的关系。

open:打开文件6
int open(const char *pathname, int flags);

系统调用Open会为该进程一个文件描述符fd,常用的flags如下:

  • O_WRONLY:表示我们以"写"的方式打开,告诉内核我们需要向文件中写入数据;
  • O_DSYNC:每次write都等待物理I/O完成,但是如果写操作不影响读取刚写入的数据,则不等待文件属性更新;
  • O_SYNC:每次write都等到物理I/O完成,包括write引起的文件属性的更新;
  • O_DIRECT:执行磁盘IO时绕过缓冲区高速缓存(内核缓冲区),从用户空间直接将数据传递到文件或磁盘设备,称为直接IO(direct IO)。因为没有了OS cache,所以会O_DIRECT降低文件的顺序读写的效率。
write:写文件7
ssize_t write(int fd, const void *buf, size_t count);

使用open打开文件获取到文件描述符之后,可以调用write函数来写文件,具体表现根据open函数参数的不同而不同弄。

fsync & fdatasync:刷新文件8
#include <unistd.h>int fsync(int fd);int fdatasync(int fd);
  • fdatasync:操作完write之后,我们可以调用fdatasync将文件数据块flush到磁盘,只要fdatasync返回成功,则可以认为数据已经写到磁盘了;
  • fsync:与O_SYNC参数类似,fsync还会更新文件metadata到磁盘;
  • sync:sync只是将修改过的块缓冲区写入队列,然后就返回,不等实际写磁盘操作完成;

为了保证文件更新成功持久化到硬盘,除了调用write方法,还需要调用fsync。

大致交互流程如下图:

image-20200520224027300

更多关于磁盘IO的相关内容,可以阅读:On Disk IO, Part 1: Flavors of IO9

**fsync性能问题:**除了刷脏页到磁盘,fsync还会同步文件metadata,而文件数据和metadata通常存放在磁盘不同地方,所以fsync至少需要两次IO操作。

对fsync性能的优化建议:由于以上性能问题,如果能够减少metadata的更新,那么就可以使用fdatasync了。因此需要确保文件的尺寸在write前后没有发生变化。为此,可以创建固定大小的文件进行写,写完则开启新的文件继续写。

3.1.2.2、innodb_flush_method

innodb_flush_method定义用于将数据刷新到InnoDB数据文件和日志文件的方法,这可能会影响I/O吞吐量。

以下是具体参数说明:

属性
命令行格式 –innodb-flush-method=value
系统变量 innodb_flush_method
范围 全局
默认值(Windows) unbuffered
默认值(Unix) fsync
有效值(Windows) unbuffered, normal
有效值(Unix) fsync, O_DSYNC, littlesync, nosync, O_DIRECT, O_DIRECT_NO_FSYNC

比较常用的是这三种:

fsync

默认值,使用fsync()系统调用来flush数据文件和日志文件到磁盘;

O_DSYNC

由于open函数的O_DSYNC参数在许多Unix系统上都存中问题,因此InnoDB不直接使用O_DSYNC。

InnoDB用于O_SYNC 打开和刷新日志文件,fsync()刷新数据文件。

表现为:写日志操作是在write函数完成,数据文件写入是通过fsync()系统调用来完成;

O_DIRECT

使用O_DIRECT (在Solaris上对应为directio())打开数据文件,并用于fsync()刷新数据文件和日志文件。此选项在某些GNU/Linux版本,FreeBSD和Solaris上可用。

表现为:数据文件写入直接从buffer pool到磁盘,不经过操作系统缓冲,日志还是需要经过操作系统缓存;

O_DIRECT_NO_FSYNC

在刷新I/O期间InnoDB使用O_DIRECT,并且每次write操作后跳过fsync()系统调用。

此设置适用于某些类型的文件系统,但不适用于其他类型的文件系统。例如,它不适用于XFS。如果不确定所使用的文件系统是否需要fsync()(例如保留所有文件元数据),请改用O_DIRECT。

如下图所示:

image-20200520232414096

为什么使用了O_DIRECT配置后还需要调用fsync()?

参考MySQL的这个bug:Innodb calls fsync for writes with innodb_flush_method=O_DIRECT10

Domas进行的一些测试表明,如果没有fsync,某些文件系统(XFS)不会同步元数据。如果元数据会更改,那么您仍然需要使用fsync(或O_SYNC来打开文件)。

例如,如果在启用O_DIRECT的情况下增大文件大小,它仍将写入文件的新部分,但是由于元数据不能反映文件的新大小,因此如果此刻系统发生崩溃,文件尾部可能会丢失。

为此:当重要的元数据发生更改时,请继续使用fsync或除O_DIRECT之外,也可以选择使用O_SYNC。

MySQL从v5.6.7起提供了O_DIRECT_NO_FSYNC选项来解决此类问题。

3.2、Change Buffer

change buffer是一种特殊的数据结构,当二级索引页(非唯一索引)不在缓冲池中时,它们会缓存这些更改 。当页面通过其他读取操作加载到缓冲池中时,再将由INSERTUPDATEDELETE操作(DML)产生的change buffer合并到buffer pool的数据页中。

为什么唯一索引不可以使用chage buffer?

针对唯一索引,如果buffer pool不存在对应的数据页,还是需要先去磁盘加载数据页,才能判断记录是否重复,这一步避免不了。

而普通索引是非唯一的,插入的时候以相对随机的顺序发生,删除和更新也会影响索引树中不相邻的二级索引树,通过使用合并缓冲,避免了在磁盘产生大量的随机IO访问获取普通索引页。

问题

当有许多受影响的行和许多辅助索引要更新时,change buffer合并可能需要几个小时,在此期间,I/O会增加,可能会导致查询效率大大降低,即使在事务提交之后,或者服务器重启之后,change buffer合并操作也会继续发生。相关阅读:Section 14.22.2, “Forcing InnoDB Recovery”

3.3、自适应哈希索引

自适应哈希索引功能由innodb_adaptive_hash_index变量启用 ,或在服务器启动时由--skip-innodb-adaptive-hash-index禁用。

3.4、Log Buffer

log buffer(日志缓冲区)用于保存要写入磁盘上的log file(日志文件)的数据。日志缓存区的内容会定期刷新到磁盘。

日志缓冲区大小由innodb_log_buffer_size变量定义 。默认大小为16MB。较大的日志缓冲区可以让大型事务在提交之前无需将redo log写入磁盘。

如果您有更新,插入或者删除多行的事务,尝试增大日志缓冲区的大小可以节省磁盘I/O。

3.4.1、配置参数

innodb_flush_log_at_trx_commit

innodb_flush_log_at_trx_commit 变量控制如何将日志缓冲区的内容写入并刷新到磁盘。

该参数控制是否严格存储ACID还是尝试获取更高的性能,可以通过该参数获取更好的性能,但是会导致在系统崩溃的过程中导致数据丢失。

可选参数:

  • 0,事务提交之后,日志只记录到log buffer中,每秒写一次日志到缓存并刷新到磁盘,尚未刷新的日志可能会丢失;
  • 1,要完全符合ACID,必须使用该值,表示日志在每次事务提交时写入缓存并刷新到磁盘;
  • 2,每次事务提交之后,日志写到page cache,每秒刷一次到磁盘,尚未刷新的日志可能会丢失;

innodb_flush_log_at_timeout

innodb_flush_log_at_timeout 变量控制日志刷新频率。可让您将日志刷新频率设置为*N秒(其中N*为1 ... 2700,默认值为1)

为了保证数据不丢失,请执行以下操作:

  • 如果启用了binlog,则设置:sync_binlog=1;
  • innodb_flush_log_at_trx_commit=1;

配置效果如下图所示:

image-20200523161540057

3.5、表空间

一个InnoDB表及其索引可以在建在系统表空间中,或者是在一个 独立表空间 中,或在 通用表空间。

  • innodb_file_per_table启用时,通常是将表存放在独立表空间中,这是默认配置;
  • innodb_file_per_table禁用时,则会在系统表空间中创建表;
  • 要在通用表空间中创建表,请使用 CREATE TABLE ... TABLESPACE语法。有关更多信息,请参见官方文档 14.6.3.3 General Tablespaces。

表空间概览图:

image-20200523161854294

表空间涉及的文件

相关文件默认在磁盘中的innodb_data_home_dir目录下:

|- ibdata1  // 系统表空间文件
|- ibtmp1  // 默认临时表空间文件,可通过innodb_temp_data_file_path属性指定文件位置
|- test/  // 数据库文件夹|- db.opt  // test数据库配置文件,包含数据库字符集属性|- t.frm  // 数据表元数据文件,不管是使用独立表空间还是系统表空间,每个表都对应有一个|- t.ibd  // 数据库表独立表空间文件,如果使用的是独立表空间,则一个表对应一个ibd文件,否则保存在系统表空间文件中

frm文件

创建一个InnoDB表时,MySQL 在数据库目录中创建一个.frm文件。frm文件包含MySQL表的元数据(如表定义)。每个InnoDB表都有一个.frm文件。

与其他MySQL存储引擎不同, InnoDB它还在系统表空间内的自身内部数据字典中编码有关表的信息。MySQL删除表或数据库时,将删除一个或多个.frm文件以及InnoDB数据字典中的相应条目。

因此,在InnoDB中,您不能仅通过移动.frm 文件来移动表。有关移动InnoDB 表的信息,请参见官方文档14.6.1.4 Moving or Copying InnoDB Tables。

ibd文件

对于在独立表空间创建的表,还会在数据库目录中生成一个 .ibd表空间文件。

通用表空间中创建的表在现有的常规表空间 .ibd文件中创建。常规表空间文件可以在MySQL数据目录内部或外部创建。有关更多信息,请参见官方文档14.6.3.3 General Tablespaces。

ibdata文件

系统表空间文件,在 InnoDB系统表空间中创建的表在ibdata中创建。

3.5.1、系统表空间

系统表空间由一个或多个数据文件(ibdata文件)组成。其中包含与InnoDB相关对象有关的元数据(InnoDB 数据字典 data dictionary),以及更改缓冲区change buffer), 双写缓冲区doublewrite buffer)和撤消日志undo logs)的存储区 。

InnoDB 如果表是在系统表空间中创建的,则系统表空间中也包含表的表数据和索引数据。

系统表空间的问题

在MySQL 5.6.7之前,默认设置是将所有InnoDB表和索引保留 在系统表空间内,这通常会导致该文件变得非常大。因为系统表空间永远不会缩小,所以如果先加载然后删除大量临时数据,则可能会出现存储问题。

在MySQL 5.7中,默认设置为 独立表空间模式,其中每个表及其相关索引存储在单独的 .ibd文件中。此默认设置使使用**Barracuda文件格式的InnoDB功能更容易使用,例如表压缩**,页外列的有效存储以及大索引键前缀(innodb_large_prefix)。

将所有表数据保留在系统表空间或单独的 .ibd文件中通常会对存储管理产生影响。

InnoDB在MySQL 5.7.6中引入了通用表空间11,这些表空间也由.ibd文件表示 。通用表空间是使用CREATE TABLESPACE语法创建的共享表空间。它们可以在MySQL数据目录之外创建,能够容纳多个表,并支持所有行格式的表。

3.5.2、独立表空间

MySQL 5.7中,配置参数:innodb_file_per_table,默认处于启用状态,这是一个重要的配置选项,会影响InnoDB文件存储,功能的可用性和I/O特性等。

启用之后,每个表的数据和索引是存放在单独的.ibd文件中的,而不是在系统表空间的共享ibdata文件中。

优点

  • 您可以更加灵活的选择数据压缩12的行格式,如:
    • 默认情况下(innodb_page_size=16K),前缀索引13最多包含768个字节。如果开启innodb_large_prefix,且Innodb表的存储行格式为 DYNAMIC 或 COMPRESSED,则前缀索引最多可包含3072个字节,前缀索引也同样适用;
  • TRUNCATE TABLE执行的更快,并且回收的空间不会继续保留,而是让操作系统使用;
  • 可以在单独的存储设备上创建每表文件表空间数据文件,以进行I / O优化,空间管理或备份。请参见 14.6.1.2 Creating Tables Externally;

缺点

  • 独立表空间中的未使用空间只能由同一个表使用,如果管理不当,会造成空间浪费;
  • 多个表需要刷盘,只能执行多次fsync,无法合并多个表的写操作,这可能会导致更多的fsync操作总数;
  • mysqld必须为每个表文件空间保留一个打开的文件句柄,如果表数量多,可能会影响性能;
  • 每个表都需要自己的数据文件,需要更多的文件描述符;

即使启用了innodb_file_per_table参数,每张表空间存放的只是数据、索引和插入缓存Bitmap页,其他数据如回滚信息、插入缓冲索引页、系统事务信息、二次写缓冲等还是存放在原来的共享表空间中。

3.5.3、通用表空间

通用表空间使用CREATE TABLESPACE语法创建。

类似于系统表空间,通用表空间是共享表空间,可以存储多个表的数据。

通用表空间比独立表空间具有潜在的内存优势,服务器在表空间的生存期内将表空间元数据保留在内存中。一个通用表空间通常可以存放多个表数据,消耗更少的表空间元数据内存。

数据文件可以放置在MySQL数据目录或独立于MySQL数据目录。

3.5.4、undo表空间

undo表空间包含undo log。

innodb_rollback_segments变量定义分配给每个撤消表空间的回滚段的数量。

undo log可以存储在一个或多个undo表空间中,而不是系统表空间中。

在默认配置中,撤消日志位于系统表空间中。SSD存储更适合undo log的I/O模式,为此,可以把undo log存放在有别于系统表空间的ssd硬盘中。

innodb_undo_tablespaces 配置选项控制undo表空间的数量。

3.5.5、临时表空间

由用户创建的非压缩临时表和磁盘内部临时表是在共享临时表空间中创建的。

innodb_temp_data_file_path 配置选项指定零时表空间文件的路径,如果未指定,则默认在 innodb_data_home_dir目录中创建一个略大于12MB 的自动扩展数据文件ibtmp1

使用ROW_FORMAT=COMPRESSED属性创建的压缩临时表,是在独立表空间中的临时文件目录中创建的 。

服务启动的时候创建临时表空间,关闭的时候销毁临时表空间。如果临时表空间创建失败,则意味着服务启动失败。

3.6、InnoDB底层逻辑存储结构

在介绍索引之前,我们有必要了解一下InnoDB底层的逻辑存储结构,因为索引是基于这个底层逻辑存储结构创建的。截止到目前,我们所展示的都仅仅是物理磁盘中的逻辑视图,接下来我们就来看看底层的视图。

3.6.1、ibd文件组织结构

现在我们打开一个表空间ibd文件,看看里面都是如何组织数据的?

如下图,表空间由段(segment)、区(extent)、页(page)组成。

InnoDB最小的存储单位是页,默认每个页大小是16k。

而InnoDB存储引擎是面向行的(row-oriented),数据按行进行存放,每个页规定最多允许存放的行数=16k/2 - 200,即7992行。

image-20200523185138539

段:如数据段、索引段、回滚段等。InnoDB存储引擎是B+树索引组织的,所以数据即索引,索引即数据。B+树的叶子节点存储的都是数据段的数据。

3.6.2、数据页结构14

名称 占用空间 描述
Fil Header 38 byte 页的基本信息,如所属表空间,上一页和下一页指针。
Page Header 56 byte 数据页专有的相关信息
Infimun + Supremum 26 byte 两个虚拟的行记录,用于限定记录的边界
User Records 动态分配 实际存储的行记录内容
Free Space 动态调整 尚未使用的页空间
Page Directory 动态调整 页中某些记录的相对位置
Fil Trailer 8 byte 校验页是否完整

关于Infimun和Supremum:首次创建索引时,InnoDB会在根页面中自动设置一个最小记录和一个最高记录,并且永远不会删除它们。最低记录和最高记录可以视为索引页开销的一部分。最初,它们都存在于根页面上,但是随着索引的增长,最低记录将存在于第一或最低叶子页上,最高记录将出现在最后或最大关键字页上。

image-20200530120303599

3.6.3、行记录结构描述15

先来讲讲Compact行记录格式,Compact是MySQL5.0引入的,设计目标是高效的存储数据,让一个页能够存放更多的数据,从而实现更快的B+树查找。

名称 描述
变长字段长度列表 字段大小最多用2个字节表示,也就是最多限制长度:2^16=65535个字节;字段大小小于255字节,则用1个字节表示;
NULL标志位 记录该行哪些位置的字段是null值
记录头信息 记录头信息信息,固定占用5个字节
列1数据 实际的列数据,NULL不占用该部分的空间
列2数据

记录头用于将连续的记录链接在一起,并用于行级锁定。

每行数据除了用户定义的列外,还有两个隐藏列:

  • 6个字节的事务ID列;
  • 7个字节的回滚指针列;
  • 如果InnoDB没有指定主键,还会增加一个6个字节的rowid列;

而记录头信息包16含如下内容:

名称 大小(bit) 描述
() 1 未知
() 1 未知
deleted_flag 1 该行是否已被删除
min_rec_flag 1 如果该记录是预定义的最小记录,则为1
n_owned 4 该记录拥有的记录数
heap_no 13 索引堆中该条记录的排序号
record_type 3 记录类型:000 普通,001 B+树节点指针,010 Infimum,011 Supremum,1xx 保留
next_record 16 指向页中下一条记录

image-20200530152925354

更详细的页结构参考官网:22.2 InnoDB Page Structure

更详细的行结构参考官网:22.1 InnoDB Record Structure

更详细的行格式参考官网:14.11 InnoDB Row Formats

根据以上格式,可以得出数据页内的记录组织方式:

image-20200530122458403

3.6.3.1、MySQL中varchar最大长度是多少

上面表格描述我们知道,一个字段最长限制是65535个字节,这是存储长度的限制。

而MySQL中对存储是有限制的,具体参考:8.4.7 Limits on Table Column Count and Row Size

  • MySQL对每个表有4096列的硬限制,但是对于给定的表,有效最大值可能会更少;
  • MySQL表的每行行最大限制为65,535字节,这是逻辑的限制;实际存储的时候,表的物理最大行大小略小于页面的一半。如果一行的长度少于一页的一半,则所有行都将存储在本地页面内。如果它超过一页的一半,那么将选择可变长度列用于外部页外存储,直到该行大小控制在半页之内为止。

而实际能够存储的字符是跟编码有关的。

背景知识:

  • MySQL 4.0版本以下,varchar(10),代表10个字节,如果存放UTF8汉字,那么只能存3个(每个汉字3字节);

  • MySQL 5.0版本以上,varchar(10),指的是10个字符,无论存放的是数字、字母还是UTF8汉字(每个汉字3字节),都可以存放10个,最大大小是65532字节

因此,Mysql5根据编码不同,存储大小也不同。

那么假设我们使用的是utf8编码,那么每个字符最多占用3个字节,也就是最多定义varchar(21845)个字符,如果是ascii编码,一个字符相当于一个字节,最多定义varchar(65535)个字符,下面我们验证下。

我们尝试创建一个这样的字段:

CREATE TABLE `t10` ( `id` int(11) NOT NULL,`a` int(11) NOT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB CHARSET=ascii ROW_FORMAT=Compact;alter table t10 add `str` varchar(21845) DEFAULT NULL;alter table t10 add `str` varchar(65535) DEFAULT NULL;

发现提示这个错误:

mysql> alter table t10 add `str` varchar(65535) DEFAULT NULL;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

原因是按照以上的行格式介绍,变长字段长度列表记录也需要占用空间,占用2个字节,另外这里是允许为空字段,在8位之内,所以NULL标志位占用1个字节,所以我们总共可以存储的字符数是:

65535 - 2 - 2 - 4 - 4=65534

其中 -2 个字节表示变长字段列表,-1表示NULL标志位,两个-4表示两个int类型字段占用大小

所以实际上能够容纳的varchar大小为:65524,我们验证下:

image-20200524121242172

3.6.3.2、行记录超过页大小如何存储

MySQL表的内部表示具有65,535字节的最大行大小限制。InnoDB 对于4KB,8KB,16KB和32KB innodb_page_size 设置,表的最大行大小(适用于本地存储在数据库页面内的数据)略小于页面的一半 。如果包含 可变长度列的InnoDB 行超过最大行大小,那么将选择可变长度列用于外部页外存储。

可变长度列由于太长而无法容纳在B树页面上,这个时候会把可变长度列存储在单独分配的磁盘页面上,这些页面称为溢出页面,这些列称为页外列。页外列的值存储在由溢出页面构成的单链接列表中。

InnoDB存储引擎支持四种行格式:REDUNDANTCOMPACTDYNAMIC,和COMPRESSED。不同的行格式,对溢出的阈值和处理方式有所区别,详细参考:14.11 InnoDB Row Formats。

COMPACT行格式处理方式

使用COMPACT行格式的表将前768个字节的变长列值(VARCHARVARBINARYBLOBTEXT类型)存储在B树节点内的索引记录中,其余的存储在溢出页上。

如果列的值等于或小于768个字节,则不使用溢出页,因此可以节省一些I / O。

如果查过了768个字节,那么会按照如下方式进行存储:

image-20200524154903041

DYNAMIC行格式处理方式

DYNAMIC行格式提供与COMPACT行格式相同的存储特性,但改进了超长可变长度列的存储能力和支持大索引键前缀。

InnoDB 可以完全在页外存储过长的可变长度列值(针对 VARCHARVARBINARYBLOBTEXT类型),而聚集索引记录仅包含指向溢出页的20字节指针。大于或等于768字节的固定长度字段被编码为可变长度字段。

image-20200524155015374

表中大字段引发的问题

如果一个表中有过多的可变长度大字段,导致一行记录太长,而整个时候使用的是COMPACT行格式,那么就可能会插入数据报错。

如,页面大小事16k,根据前面描述我们知道,MySQL限制一页最少要存储两行数据,如果很多可变长度大字段,在使用COMPACT的情况下,仍然会把大字段的前面768个字节存在索引页中,可以算出最多支持的大字段:1024 * 16 / 2 / 768 = 10.67,那么超过10个可变长度大字段就会插入失败了。

这个时候可以把row format改为:DYNAMIC。

3.7、索引

前面我们了解了InnoDB底层的存储结构,即:以B+树的方式组织数据页。另外了解了数据页中的数据行的存储方式。

而构建B+树索引的时候必须要选定一个或者多个字段作为索引的值,如果索引选择的是主键,那么我们就称为聚集索引,否则就是二级索引。

为什么MySQL使用B+树?

  • 哈希表虽然可以提供O(1)的单行数据操作性能,但却不能很好的支持排序和范围查找,会导致全表扫描;
  • B树可以再非叶子节点存储数据,但是这可能会导致查询连续数据的时候增加更多的I/O操作;
  • 而B+树数据都存放在叶子节点,叶子节点通过指针相互连接,可以减少顺序遍历时产生的额外随机I/O

更新详细解释: 为什么 MySQL 使用 B+ 树17

3.7.1、聚集索引

了解到上面的底层逻辑存储结构之后,我们进一步来看看InnoDB是怎么通过B+树来组织存储数据的。

首先来介绍下聚集索引。

聚集索引

主键索引的InnoDB术语。

下面我们创建一张测试表,并插入数据,来构造一颗B+树:

CREATE TABLE t20 (
id int NOT NULL,
a int NOT NULL,
b int,
c int,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;insert into t20 values(20, 1, 2, 1);
insert into t20 values(40, 1, 2, 5);
insert into t20 values(30, 3, 2, 4);
insert into t20 values(50, 3, 6, 2);
insert into t20 values(10, 1, 1, 1);

可以看到,虽然我们是id乱序插入的,但是插入之后查出来的确是排序好的:

image-20200524162034526

这个排序就是B+索引树构建的。

我们可以通过这个在线的动态演示工具来看看B+树的构造过程,最终结果如下:

image-20200524162043982

实际存放在数据库中的模型因页面大小不一样而有所不同,这里为了简化模型,我们按照B+树的通用模型来解释数据的存储结构。

类似的,我们的数据也是这种组织形式的,该B+树中,我们以主键为索引进行构建,并且把完整的记录存到对应的页下面:

image-20200524170732546

其中蓝色的是索引页,橙色的是数据页。

每个页的大小默认为16k,如果插入新的数据行,这个时候就要申请新的数据页了,然后挪动部分数据过去,重新调整B+树,这个过程称为页分裂,这个过程会影响性能。

相反的,如果InnoDB索引页的填充因子下降到之下MERGE_THRESHOLD,默认情况下为50%(如果未指定),则InnoDB尝试收缩索引树以释放页面。

自增主键的插入是递增顺序插入的,每次添加记录都是追加的,不涉及到记录的挪动,不会触发叶子节点的分裂,而一般业务字段做主键,往往都不是有序插入的,写成本比较高,所以我们更倾向于使用自增字段作为主键。

聚集索引注意事项

  • 当在表上面定义了PRIMARY KEY之后,InnoDB会把它作为聚集索引。为此,为你的每个表定义一个PRIMARY KEY。如果没有唯一并且非空的字段或者一组列,那么请添加一个自增列;
  • 如果您没有为表定义PRIMARY KEY,则MySQL会找到第一个不带null值的UNIQUE索引,并其用作聚集索引;
  • 如果表没有PRIMARY KEY或没有合适的UNIQUE索引,则InnoDB 内部会生成一个隐藏的聚集索引GEN_CLUST_INDEX,作为行ID,行ID是一个6字节的字段,随着数据的插入而自增。

聚集索引查找

根据索引进行查找id=50的记录,如下图,沿着B+树一直往下寻找,最终找到第四页**,然后把该页加载到buffer pool中,在缓存中遍历对比查找**,由于里面的行记录是顺序组织的,所以很快就可以定位到记录了。

image-20200524232033153

3.7.2、辅助索引

除了聚集索引之外的所有索引都称为辅助索引(二级索引)。在InnoDB中,辅助索引中每个记录都包含该行的主键列以及为辅助索引指定的列。

在辅助索引中查找到记录,可以得到记录的主键索引ID,然后可以通过这个主键索引ID去聚集索引中搜索具体的记录,这个过程称为回表操作。

如果主键较长,则辅助索引将使用更多空间,因此具有短的主键是有利的。

下面我们给刚刚的表添加一个组合联合索引

-- 添加多一个字段
alter table t20 add column d varchar(20) not null default '';
-- 添加一个联合索引
alter table t20 add index idx_abc(a, b, c);

添加之后组合索引B+树如下,其中索引key为abc三个字段的组合,索引存储的记录为主键ID:

image-20200525000141742

覆盖索引(Using index)

InnoDB存储引擎支持覆盖索引,即从辅助索引中就可以得到查询的记录,而不需要回表去查询聚集索引中的记录,从而减少大量的IO操作。下面的查询既是用到了覆盖索引 idx_abc:

select a, b from t20 where a > 2;

执行结果如下:

image-20200525000655179

可以发现,Extra这一列提示Using index,使用到了覆盖索引,扫描的行数为2。注意:这里的扫描行数指的是MySQL执行器从引擎取到两条记录,引擎内部可能会遍历到多条记录进行条件比较。

最左匹配原则

由于InnoDB索引式B+树构建的,因此可以利用索引的“最左前缀”来定位记录。

也就是说,不仅仅是用到索引的全部定义字段会走索引,只要满足最左前缀,就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左n个字段。

索引条件下推(Using index condition)

索引条件下推 Index Condition Pushdown (ICP),是针对MySQL使用索引从表中检索行的情况的一种优化。

为什么叫下推呢,就是在满足要求的情况下,把索引的条件丢给存储引擎去判断,而不是把完整的记录传回MySQL Server层去判断。

ICP支持range, ref, eq_ref, 和 ref_or_null类型的查找,支持MyISAM和InnoDB存储引擎。

不能将引用子查询的条件下推,触发条件不能下推。详细规则参考:Index Condition Pushdown

如果不使用ICP,则存储引擎将遍历索引以在聚集索引中定位行,并将结果返回给MySQL Server层,MySQL Server层继续根据WHERE条件进行筛选行。

启用ICP后,如果WHERE可以仅使用索引中的列来评估部分条件,则MySQL Server层会将这部分条件压入WHERE条件下降到存储引擎。然后,存储引擎通过使用索引条目来判断索引条件,在满足条件的情况下,才回表去查找记录返回给MySQL Server层。

ICP的目标是减少回表扫描的行数,从而减少I / O操作。对于InnoDB表,ICP仅用于二级索引。

使用索引下推的时候,执行计划中的Extra会提示:Using index condition,而不是Using index,因为必须回表查询整行数据。Using index代表使用到了覆盖索引。

3.8、InnoDB Data Directory

InnoDB数据字典(Data Directory)存放于系统表空间中,主要包含元数据,用于追踪表、索引、表字段等信息。由于历史的原因,InnoDB数据字典中的元数据与.frm文件中的元数据重复了。

3.9、Doublewrite Buffer

双写缓冲区(Doublewrite Buffer)是一个存储区,是InnoDB在tablespace上的128个页(2个区),大小是2MB18

版本区别:在MySQL 8.0.20之前,doublewrite缓冲区存储区位于InnoDB系统表空间中。从MySQL 8.0.20开始,doublewrite缓冲区存储区位于doublewrite文件中。

本文基于MySQL 5.7编写。

操作系统写文件是以4KB为单位的,那么每写一个InnoDB的page到磁盘上,操作系统需要写4个块。如果写入4个块的过程中出现系统崩溃,那么会导致16K的数据只有一部分写是成功的,这种情况下就是partial page write(部分页写入)问题。

InnoDB这个时候是没法通过redo log来恢复的,因为这个时候页面的Fil Trailer(Fil Trailer 主要存放FIL_PAGE_END_LSN,主要包含页面校验和以及最后的事务)中的数据是有问题的。

为此,每当InnoDB将页面写入到数据文件中的适当位置之前,都会首先将其写入双写缓冲区。只有将缓冲区安全地刷新到磁盘后,InnoDB才会将页面写入最终的数据文件。

image-20200526221407586

如果在页面写入过程中发生操作系统或者mysqld进程崩溃,则InnoDB可以在崩溃恢复期间从双写缓冲区中找到页面的完好副本用于恢复。恢复时,InnoDB扫描双写缓冲区,并为缓冲区中的每个有效页面检查数据文件中的页面是否完整。

如果系统表空间文件(“ ibdata文件 ”)位于支持原子写的Fusion-io设备上,则自动禁用双写缓冲,并且将Fusion-io原子写用于所有数据文件。

3.10、Redo Log

重做日志(Redo Log)主要适用于数据库的崩溃恢复,用于实现数据的完整性。

重做日志由两部分组成:

  • 重做日志缓冲区 Log Buffer;
  • 重做日志文件,重做日志文件在磁盘上由两个名为ib_logfile0ib_logfile1的物理文件表示。

image-20200526222744741

为了实现数据完整性,在脏页刷新到磁盘之前,必须先把重做日志写入到磁盘。除了数据页,聚集索引、辅助索引以及Undo Log都需要记录重做日志。

3.10.1、Redo Log在事务中的写入时机

在事务中,除了写Redo log,还需要写binlog,为此,我们先来简单介绍下binlog。

3.10.1.1、binlog

全写:Binary Log,二进制log。二进制日志是一组日志文件。其中包含有关对MySQL服务器实例进行的数据修改的信息。

Redo Log是InnoDB引擎特有的,而binlog是MySQL的Server层实现的,所有引擎都可以使用。

Redo Log的文件是循环写的,空间会用完,binlog日志是追加写的,不会覆盖以前的日志。

binlog主要的目的:

  • 主从同步,主服务器将二进制日志中包含的事件发送到从服务器,从服务器执行这些事件,以保持和主服务器相同的数据更改;
  • 某些数据恢复操作需要使用二进制日志,还原到某一个备份点。

binlog主要是用于主从同步和数据恢复,Redo Log主要是用于实现事务数据的完整性,让InnoDB具有不会丢失数据的能力,又称为crash-safe。

binlog日志的两种记录形式:

  • 基于SQL的日志记录:事件包含产生数据更改(插入,新增,删除)的SQL语句;
  • 基于行的日志记录:时间描述对单个行的更改。

混合日志记录默认情况下使用基于语句的日志记录,但根据需要自动切换到基于行的日志记录。

3.10.1.2、Redo Log在事务中的写入时机

简单的介绍完binlog,我们再来看看Redo Log的写入流程。

假设我们这里执行一条sql

update t20 set a=10 where id=1;

执行流程如下:

image-20200529000923116

3.10.2、如何保证数据不丢失

前面我们介绍Log Buffer的时候,提到过,为了保证数据不丢失,我们需要执行以下操作:

  • 如果启用了binlog,则设置:sync_binlog=1;
  • innodb_flush_log_at_trx_commit=1;
  • sync_binlog=0:表示每次提交事务都只 write,不 fsync;
  • sync_binlog=1:表示每次提交事务都会执行 fsync;
  • sync_binlog=N(N>1) :表示每次提交事务都 write,但累积 N 个事务后才 fsync。

这两个的作用相当于在上面的流程最后一步,提交事务接口返回Server层之前,把binlog cache和log buffer都fsync到磁盘中了,这样就保证了数据的落盘,不会丢失,即使奔溃了,也可以通过binlog和redo log恢复数据相关流程如下:

image-20200529001035132

在磁盘和内存中的处理流程如下面编号所示:

image-20200529001256504

其中第四步log buffer持久化到磁盘的时机为:

  • log buffer占用的空间即将达到innodb_log_buffer_size一半的时候,后台线程主动写盘;
  • InnoDB后台有个线程,每隔1秒会把log buffer刷到磁盘;
  • 由于log buffer是所有线程共享的,当其他事务线程提交时也会导致已写入log buffer但还未提交的事务的redo log一起刷新到磁盘

其中第五步:脏页刷新到磁盘的时机为:

  • 系统内存不足,需要淘汰脏页的时候,要把脏页同步回磁盘;
  • MySQL空闲的时候;
  • MySQL正常关闭的时候,会把脏页flush到磁盘。

参数innodb_max_dirty_pages_pct是脏页比例上限,默认值是 75%。

为什么第二步 redo log prepare状态也要写磁盘?

因为这里先写了,才能确保在把binlog写到磁盘后崩溃,能够恢复数据:如果判断到redo log是prepare状态,那么查看是否存XID对应的binlog,如果存在,则表示事务成功提交,需要用prepare状态的redo log进行恢复。

这样即使崩溃了,也可以通过redo log来进行恢复了,恢复流程如下:

Redo Log是循环写的,如下图:

  • writepos记录了当前写的位置,一边写位置一边往前推进,当writepos与checkpoint重叠的时候就表示logfile写满了,绿色部分表示是空闲的空间,红色部分是写了redo log的空间;
  • checkpoint处标识了当前的LSN,每当系统崩溃重启,都会从当前checkpoint这个位置执行重做日志,根据重做日志逐个确认数据页是否没问题,有问题就通过redo log进行修复。

image-20200528235418486

LSN Log Sequence Number的缩写。代表日志序列号。在InnoDB中,LSN占用8个字节,单调递增,LSN的含义:

  • 重做日志写入的总量;
  • checkpoint的位置;
  • 页的版本;

除了重做日志中有LSN,每个页的头部也是有存储了该页的LSN,我们前面介绍页面格式的时候有介绍过。

在页中LSN表示该页最后刷新时LSN的大小。19

3.11、Undo Logs

上面说的redo log记录了事务的行为,可以通过其对页进行重做操作,但是食物有时候需要进行回滚,这时候就需要undo log了20

**关于Undo Log的存储:**InnoDB中有回滚段(rollback segment),每个回滚段记录1024个undo log segment,在每个undo log segment段中进行申请undo页。系统表空间偏移量为5的页记录了所有的rollback segment header所在的页。

image-20200530123839227

3.11.1、undo log的格式

根据行为不同分为两种:

insert undo log

insert undo log:只对事务本身可见,所以insert undo log在事务提交后可直接删除,无需执行purge操作;

insert undo log主要记录了:

next 记录下一个undo log的位置
type_cmpl undo的类型:insert or update
*undo_no 记录事务的ID
*table_id 记录表对象
*len1, col1 记录列和值
*len2, col2 记录列和值
start 记录undo log的开始位置

假设在事务1001中,执行以下sql,t20的table_id为10:

insert into t20(id, a, b, c, d) values(12, 2, 3, 1, "init")

那么对应会生成一条undo log:

image-20200530165013967

update undo log

update undo log:执行update或者delete会产生undo log,会影响已存在的记录,为了实现MVCC(后边介绍),update undo log不能再事务提交时立刻删除,需要将事务提交时放入到history list上,等待purge线程进行最后的删除操作。

update undo log主要记录了:

next 记录下一个undo log的位置
type_cmpl undo的类型:insert or update
*undo_no undo日志编号
*table_id 记录表对象
info_bits
*DATA_TRX_ID 事务的ID
*DATA_ROLL_PTR 回滚指针
*len1, i_col1 n_unique_index
*len2, i_col2
n_update_fields 以下是update vector信息,表示update操作导致发送改变的列
*pos1, *len1, u_old_col1
*pos2, *len2, u_old_col2
n_bytes_below
*pos, *len, col1
*pos, *len, col2
start 记录undo log的开始位置

假设在事务1002中,执行以下sql,t20的table_id为10:

update t20 set d="update1" where id=60;

那么对应会生成一条undo log:

image-20200530171944498

如上图,每回退应用一个undo log,就回退一个版本,这就是MVCC(Multi versioning concurrency control)的实现原理。

下面我们在执行一个delete sql:

delete from t20 where id=60;

对应的undo log变为如下:

image-20200530172640974

如上图,实际的行记录不会立刻删除,而是在行记录头信息记录了一个deleted_flag标志位。最终会在purge线程purge undo log的时候进行实际的删除操作,这个时候undo log也会清理掉。

3.11.2、MVCC实现原理

如上图所示,MySQL只会有一个行记录,但是会把每次执行的sql导致行记录的变动,通过undo log的形式记录起来,undo log通过回滚指针连接在一起,这样我们想回溯某一个版本的时候,就可以应用undo log,回到对应的版本视图了。

我们知道InnoDB是支持RC(Read Commit)和RR(Repeatable Read)事务隔离级别的,而这个是通过一致性视图(consistent read view)实现的。

一个事务开启瞬间,所有活跃的事务(未提交)构成了一个视图数组,InnoDB就是通过这个视图数组来判断行数据是否需要undo到指定的版本:

image-20200530213342612

RR事务隔离级别

假设我们使用了RR事务隔离级别。我们看个例子:

如下图,假设id=60的记录a=1

image-20200530215747142

事务C启动的瞬间,活跃的事务如下图黄色部分所示:

image-20200530222622858

也就是对于事务A、事务B、事务C,他们能够看到的数据只有是行记录中的最大事务IDDATA_TRX_ID<=11的,如果大于,那么只能通过undo进行回滚了。如果TRX_ID=当前事务id,也可以看到,即看到自己的改动。

另外有一个需要注意的:

  • 在RR隔离级别下,当事务更新事务的时候,只能用当前读来获取最新的版本数据来更新,如果当前记录的行锁被其他事务占用,就需要进入所等待;
  • 在RC隔离级别下,每个语句执行都会计算出新的一致性视图。

所以我们分析上面的例子的执行流程:

  • 事务C执行update,执行当前读,拿到的a=1,然后+1,最终a=2,同时添加一个TRX_ID=11的undo log;
    • image-20200530221027891
  • 事务B执行select,使用快照读,记录的DATA_TRX_ID > 11,所以需要通过undo log回滚到DATA_TRX_ID=11的版本,所以拿到的a是1;
  • 事务B执行update,需要使用当前读,拿到最新的记录,a=2,然后加1,最终a=3;
    • image-20200530221734284
  • 事务B执行select,拿到当前最新的版本,为自己的事务id,所以得到a=3;
  • 事务A执行select,使用快照读,记录的DATA_TRX_ID > 11,所以需要通过undo log回滚到DATA_TRX_ID=11的版本,所以拿到的a是1。
  • 如果是RC隔离级别,执行select的时候会计算出新的视图,新的视图能够看到的最大事务ID=14,由于事务B还没提交,事务C提交了,所以可以得到a=2:
    • image-20200530223051094

总结

  • 数据完整性依靠:redo log
  • 事务隔离级别的实现依靠MVCC,MVCC依靠undo log实现
  • IO性能提升方式:buffer pool加快查询效率和普通索引更新的效率,log buffer对日志写的性能提升
  • 查询性能提升依赖于索引,底层用页存储,字段越小页存储越多行记录,查询效率越快;自增字段作为聚集索引可以加快插入操作;
  • 故障恢复:双写缓冲区、redo log
  • 主从同步:binlog

本文内容比较多,看完之后需要多梳理,最后大家可以对照着这个思维导图回忆一下,这些内容是否都记住了:

image-20200531191959183

image-20200531180757758


这篇文章的内容就差不多介绍到这里了,能够阅读到这里的朋友真的是很有耐心,为你点个赞。

本文为arthinking基于相关技术资料和官方文档撰写而成,确保内容的准确性,如果你发现了有何错漏之处,烦请高抬贵手帮忙指正,万分感激。

大家可以关注我的博客:itzhai.com 获取更多文章,我将持续更新后端相关技术,涉及JVM、Java基础、架构设计、网络编程、数据结构、数据库、算法、并发编程、分布式系统等相关内容。

如果您觉得读完本文有所收获的话,可以关注我的账号,或者点赞吧,码字不易,您的支持就是我写作的最大动力,再次感谢!

关注我的公众号,及时获取最新的文章。

更多文章

  • JVM系列专题:公众号发送 JVM

本文作者: arthinking

博客链接: https://www.itzhai.com/database/insight-into-the-underlying-architecture-of-mysql-buffer-and-disk.html

洞悉MySQL底层架构:游走在缓冲与磁盘之间

版权声明: BY-NC-SA许可协议:创作不易,如需转载,请务必附加上博客链接,谢谢!


References


  1. innodb_data_home_dir. Retrieved from https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_data_home_dir ↩︎

  2. ib_buffer_pool. Retrieved from https://dev.mysql.com/doc/refman/5.6/en/innodb-preload-buffer-pool.html ↩︎

  3. ib_logfile0. Retrieved from https://dev.mysql.com/doc/refman/5.7/en/innodb-redo-log.html ↩︎

  4. ibtmp1. Retrieved from https://dev.mysql.com/doc/refman/5.7/en/innodb-temporary-tablespace.html ↩︎

  5. db.opt. Retrieved from https://dev.mysql.com/doc/refman/8.0/en/data-dictionary-file-removal.html ↩︎

  6. Linux Programmer’s Manual - OPEN(2). (2020-02-09). Retrieved from http://man7.org/linux/man-pages/man2/open.2.html ↩︎

  7. man-pages.write. (2019-10-10). Retrieved from http://man7.org/linux/man-pages/man2/write.2.html ↩︎

  8. man-pages.fdatasync. (2019-03-06). Retrieved from http://man7.org/linux/man-pages/man2/fdatasync.2.html ↩︎

  9. On Disk IO, Part 1: Flavors of IO. medium.com. Retrieved from https://medium.com/databasss/on-disk-io-part-1-flavours-of-io-8e1ace1de017 ↩︎

  10. Innodb calls fsync for writes with innodb_flush_method=O_DIRECT. Retrieved from https://bugs.mysql.com/bug.php?id=45892 ↩︎

  11. 14.6.3.3 General Tablespaces. Retrieved from https://dev.mysql.com/doc/refman/5.7/en/general-tablespaces.html ↩︎

  12. MYSQL INNODB表压缩. (2018-03-09). Retrieved from https://cloud.tencent.com/developer/article/1056453 ↩︎

  13. 前缀索引,一种优化索引大小的解决方案. (2015-03-03). Retrieved from https://www.cnblogs.com/studyzy/p/4310653.html ↩︎

  14. MySQL Internals Manual - innodb page structure[EB/OL]. (2020-05-04). Retrieved 2020-0530, from https://dev.mysql.com/doc/internals/en/innodb-page-structure.html ↩︎

  15. official.MySQL Internals Manual - innodb record structure[EB/OL]. (2020-05-04). Retrieved 2020-0530, from https://dev.mysql.com/doc/internals/en/innodb-record-structure.html ↩︎

  16. 姜承尧. MySQL技术内幕-InnoDB存储引擎第二版[M]. 机械工业出版社, 2013-5:104. ↩︎

  17. 为什么 MySQL 使用 B+ 树. draveness.me. (2019-12-11). Retrieved from https://draveness.me/whys-the-design-mysql-b-plus-tree/ ↩︎

  18. InnoDB DoubleWrite Buffer as Read Cache using SSDs∗. Retrieved from https://www.usenix.org/legacy/events/fast12/poster_descriptions/Kangdescription2-12-12.pdf ↩︎

  19. 姜承尧. MySQL技术内幕-InnoDB存储引擎第二版[M]. 机械工业出版社, 2013-5:302-303. ↩︎

  20. 姜承尧. MySQL技术内幕-InnoDB存储引擎第二版[M]. 机械工业出版社, 2013-5:306. ↩︎

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. Qlearning、sarsa以及sarsa_lambda

    Qlearning算法import numpy as np import gym import random if __name__ == __main__: env = gym.make("FrozenLake-v0") env.render() action_size = env.action_space.n print("Action size ", action_size) state_size = env.observation_spac…...

    2024/5/1 22:41:04
  2. SIFT算法详解

    尺度不变特征变换匹配算法详解Scale Invariant Feature Transform(SIFT)Just For Funzdd zddmail@gmail.com or (zddhub@gmail.com)对于初学者,从David G.Lowe的论文到实现,有许多鸿沟,本文帮你跨越。如果你学习SIFI得目的是为了做检索,也许 OpenSSE 更适合你,欢迎使用。…...

    2024/4/18 0:30:20
  3. ICE协议下NAT穿越的实现(STUN&TURN)

    对下文的内容添加举例说明:四种NAT类型:RFC3489 中将 NAT 的实现分为四大类:Full Cone NAT (完全锥形 NAT)Restricted Cone NAT (限制锥形 NAT ,可以理解为 IP 限制,Port不限制)Port Restricted Cone NAT (端口限制锥形 NAT,IP+Port 限制)Symmetric NAT (对称 NAT)…...

    2024/5/1 23:12:25
  4. 工作室成员2020春招总结

    写在开头 本人是双非本科生,目前大三,大学期间主要学习java,了解一点python,主要是做java服务端开发。大学期间参加了学校的一些技术工作室。2020年2月我正式开始了自己的春招之旅,先后获得了cvte、腾讯、美团、阿里等公司的实习offer,也正是在这个过程中,我学到了很多东…...

    2024/4/16 8:04:50
  5. HTTP 协议与原理分析之一

    一、网络协议分层网络协议分层,经典的五层模型,分为客户端和服务端。客户端是分为应用层到传输层,再到网络层,到数据链路层,最后到物理层。服务端是物理层到数据链路层,再到网络层,到传输层,最后到应用层。应用层最常见的是 HTTP、FTP等等,传输层最常见的是TCP、UDP等…...

    2024/4/19 15:11:07
  6. 25FPS实时图像去雨算法RSEN | Residual Squeeze-and-Excitation Network for Fast Image Deraining

    首先,从论文创新方面来说,可以说是毫无创新。但是,其25FPS的速度对于图像去雨来说还是一个很好很实用的模型,而且性能还能够SOTA! 论文地址:https://arxiv.org/pdf/2006.00757.pdfAbstract:图像去雨是一项重要的图像处理任务,因为雨水条纹不仅会严重降低图像的视觉质量…...

    2024/5/2 0:12:38
  7. 基于svd矩阵分解的推荐算法推荐网课平台(根据网速,功能以及用户的喜好推荐)包括ui界面

    背景 由于新型冠状肺炎疫情所致,为了保证学生学业进度,国家教育部提出“停课不停学”的要求。于是,各地教育部门详细地制定了关于线上教学的方案,线上教学成为广大学生与老师最受欢迎与信赖的上课方式。然而,线上教学也面临诸多问题,如上课方式的选择,有的线上教学软件只…...

    2024/4/28 11:07:57
  8. 还觉得linux命令难吗,看这篇2w多字的linux命令详解,通俗易懂

    序言本篇文章主要讲解了一些linux常用命令,主要讲解模式是,命令介绍、命令参数格式、命令参数、命令常用参数示例。由于linux命令较多,我还特意选了一些日常使用较为频繁的命令进行讲解,但还是免不了文章很长,建议大家收藏起来,用到的时候不会了再来阅读。当然学习linux命…...

    2024/5/1 23:53:08
  9. 2020春招总结

    写在开头 本人是双非本科生,目前大三,大学期间主要学习java,了解一点python,主要是做java服务端开发。大学期间参加了学校的一些技术工作室。2020年2月我正式开始了自己的春招之旅,先后获得了cvte、腾讯、美团、阿里等公司的实习offer,也正是在这个过程中,我学到了很多东…...

    2024/5/2 1:54:31
  10. 嵌入式linux应用开发A :课程作业3

    课程作业3 【3.1 安装NFS服务】 1、NFS允许计算机的客户-服务器模型,服务器实施共享文件系统,以及客户端所连接的存储。 A.对 B.错 答:对 2、nfs(network file system)是一种基于___的文件系统 答:网络文件系统 【3.2NFS服务配置实例】 1、NFS服务配置的一般步骤: A.设置共…...

    2024/4/24 10:12:16
  11. Shell脚本学习之expect命令

    一、概述 我们通过Shell可以实现简单的控制流功能,如:循环、判断等。但是对于需要交互的场合则必须通过人工来干预,有时候我们可能会需要实现和交互程序如telnet服务器等进行交互的功能。而expect就使用来实现这种功能的工具。expect是一个免费的编程工具语言,用来实现自动…...

    2024/4/24 10:12:15
  12. 数据分析与挖掘学习|python001

    python介绍 什么是python python是一种解释型、面向对象的语言。 python特点 1.可读性强 2.简洁 由c语言开发,不再有c语言中指针等复杂数据类型,简洁性让开发难度和代码幅度降低,开发任务大大简化。 3.面向对象 4.免费开源 5.可移植性和跨平台 python会被编译成与操作系统相…...

    2024/5/2 1:06:30
  13. day02

    颜色分类问题 leetcode 75这道题我开始当成排序题做了,因为要求是进行原地排序,所以我使用的是插入排序 public static void sortColors(int[] nums) { // 使用插入排序if (nums.length<2||nums==null) return;for (int i = 1; i <nums.length ; i++) {for (int…...

    2024/4/24 10:12:13
  14. Deep-Learning Processor(2014-2017)

    本文汇总了近年来关于Deep-Learning Processor领域的相关论文。 2014 ASPLOS Chen, Tianshi, et al. “DianNao: a small-footprint high-throughput accelerator for ubiquitous machine-learning.” architectural support for programming languages and operating systems …...

    2024/4/24 10:12:13
  15. Qlearnin、sarsa以及sarsa_lambda

    Qlearning算法import numpy as np import gym import random if __name__ == __main__: env = gym.make("FrozenLake-v0") env.render() action_size = env.action_space.n print("Action size ", action_size) state_size = env.observation_spac…...

    2024/4/24 10:12:12
  16. 街景字符识别比赛心得

    阿里天池-零基础入门CV赛事(街景字符识别编码)-Task 5 模型集成1 模型集成1.1 学习目标1.2 集成学习方法1.3 深度学习中的集成学习1.3.1 dropout1.3.2 TTA1.3.3 Snapshot 1 模型集成 本章讲解的知识点包括:集成学习方法、深度学习中的集成学习和结果后处理思路。 1.1 学习目…...

    2024/4/24 10:12:11
  17. 无意中发现的方法:一招让你的 IntelliJ Idea 飞起来

    一、引言 最近工作中使用到了 IntelliJ Idea,说实在的,不太熟悉这个 IDE。 不知道为什么,对比 Eclipse 和 IntelliJ Idea,在我的电脑上,竟然是 IntelliJ Idea 比 Eclipse 运行的更卡一些。尤其是 IntelliJ Idea 的内存占用,简直惊人,在我的办公电脑上,竟然达到了 恐怖的…...

    2024/4/24 10:12:09
  18. 机器学习2 模型评估选择

    真实情况 预测情况 正例 反例 正例 TP(预测为正例,正确) FN(预测为反例,错误) 反例 FP(预测为正例,错误) TN(预测为反例,正确)真正例率等于在真实情况为正例的时候,预测为正例/总的正例数 真反例率等于在真实情况为反例的时候,预测为反例/总的反例数 查准率等于预…...

    2024/4/24 10:12:08
  19. 《Python编程:从入门到实践》第六章笔记

    6.1 一个简单的字典 >>> alien_0 = {color:green,point:5} >>> alien_0 {color: green, point: 5}6.2 使用字典 在Python中,字典是一系列键-值对,可将任何Python对象用作字典中的值。 6.2.1 访问字典中的值 >>> alien_0[color] green6.2.2 添加键…...

    2024/4/24 10:12:10
  20. Spring_Days_01

    今天我们来手写一下Spring中的IOC过程。 程序的耦合和解耦合 1、程序的耦合:程序间的依赖关系 2、分类:类之间的依赖 方法间的依赖3、解耦合:降低程序间的依赖关系 实际开发中应该做到:编译期不依赖,运行时才依赖。 这里给大家举个例子,我们之前学习的JDBC的过程。OK,看…...

    2024/4/18 16:08:13

最新文章

  1. Window(Qt/Vs)软件添加版本信息

    Window&#xff08;Qt/Vs&#xff09;软件添加版本信息 文章目录 Window&#xff08;Qt/Vs&#xff09;软件添加版本信息VS添加版本信息添加资源文件添加版本定义头自动更新版本添加批处理脚本设置生成事件 Qt添加版本信息添加资源文件文件信息修改自动更新版本 CMake添加版本信…...

    2024/5/2 2:29:33
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 前端三剑客 —— JavaScript (第四节)

    目录 内容回顾&#xff1a; 函数 *** 什么是函数 函数定义 函数调用 函数使用示例 匿名函数 无参函数 箭头函数 1、无参无返回值 2、无参有返回值 3、无参有返值&#xff0c;但函数体只有一条语句&#xff0c;则大括号可以省略&#xff0c; return 语句可以省略 4…...

    2024/5/1 10:22:14
  4. CSS3 高级- 复杂选择器、内容生成、变形(transform)、过渡(transition)、动画(animation)

    文章目录 一、复杂选择器兄弟选择器:选择平级元素的唯一办法属性选择器:1、通用:基本用不着,太泛了2、自定义:4种伪类选择器:1、目标伪类:2、结构伪类:3、元素状态伪类:4、伪元素选择器:应用于文字,使网页看起来想杂志5、否定伪类:选择器:not([本选择器的条件]) /*…...

    2024/5/1 13:11:32
  5. 分布式链路追踪与云原生可观测性

    分布式链路追踪系统历史 Dapper, a Large-Scale Distributed Systems Tracing Infrastructure - Google Dapper&#xff0c;大规模分布式系统的跟踪系统大规模分布式系统的跟踪系统&#xff1a;Dapper设计给我们的启示 阿里巴巴鹰眼技术解密 - 周小帆京东云分布式链路追踪在金…...

    2024/5/1 14:08:57
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/30 18:14:14
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/30 18:21:48
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/30 9:43:22
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57