MySQL日志文件:redo log、undo log和binlog详解
MySQL 日志 主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。其中,比较重要的还要属二进制日志 binlog(归档日志)和事务日志 redo log(重做日志)和 undo log(回滚日志)。1、重做日志(redo log)2、回滚日志(undo log)3、归档日志(binlog)4、错误日志(errorlog)5、慢查询日志(slow query log)6、一般查询
前言
MySQL 日志 主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。其中,比较重要的还要属二进制日志 binlog(归档日志)和事务日志 redo log(重做日志)和 undo log(回滚日志)。
MySQL日志主要包括七种:
1、重做日志(redo log)
2、回滚日志(undo log)
3、归档日志(binlog)
4、错误日志(errorlog)
5、慢查询日志(slow query log)
6、一般查询日志(general log)
7、中继日志(relay log)
一、redo log
redo log(重做日志)是InnoDB存储引擎独有的,它让MySQL拥有了崩溃恢复能力。
1.1 技术名词前瞻
。WAL 技术
WAL 的全称是 Write-Ahead Logging(预写日志),是数据库系统中常见的一种手段,用于保证数据操作的原子性和持久性。在使用 WAL 的系统中,
所有的修改在提交之前都要先写入 log 文件中。它的关键点就是「修改并不直接写入到数据库文件中,而是写入到另外一个称为 WAL 的文件中;如果事务失败,
WAL 中的记录会被忽略,撤销修改;如果事务成功,它将在随后的某个时间被写回到数据库文件中,提交修改。」。
一方面 WAL 中记录事务的更新内容,通过 WAL 将随机的脏页写入变成顺序的日志刷盘,另一方面,WAL 通过 buffer 的方式改单条磁盘刷入为缓冲批
量刷盘,再者从 WAL 数据到最终数据的同步过程中可以采用并发同步的方式。这样极大提升数据库写入性能,因此,WAL 的写入能力决定了数据库整体性能的上限,
尤其是在高并发时。
。crash-safe
crash-safe 本质上就是落盘处理,将数据持久化到了磁盘上,即使断电重启也不会丢失。比如 MySQL 实例挂了或宕机了,重启时,InnoDB存储引擎会使用
redo log恢复数据,保证数据的持久性与完整性。
在MySQL中,如果每次的更新操作都需要写进binlog记录,磁盘要找到对应的那条记录,更新后再保存整页的数据,整个过程 IO 成本、查找成本都很高。为了解决这个问题,MySQL的设计者使用了redo log来保存最近的数据变更记录,这样的设计被称为WAL技术。
有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。
具体来说,当有一条update语句要执行的时候,InnoDB 引擎就会先把“在某个数据页上做了什么修改”记录到重做日志缓存(redo log buffer)里,接着刷盘到 redo log 文件里,这个时候更新就算完成了。同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面。
理想情况,事务一提交就会进行刷盘操作,但实际上,刷盘的时机是根据策略来进行的。
小贴士:每条 redo 记录由“表空间号+数据页号+偏移量+修改数据长度+具体修改的数据”组成
1.2 刷盘时机
InnoDB 存储引擎为 redo log 的刷盘策略提供了 innodb_flush_log_at_trx_commit 参数,它支持三种策略:
0 :设置为 0 的时候,表示每次事务提交时不进行刷盘操作
1 :设置为 1 的时候,表示每次事务提交时都将进行刷盘操作(默认值)
2 :设置为 2 的时候,表示每次事务提交时都只把 redo log buffer 内容写入 page cache
innodb_flush_log_at_trx_commit 参数默认为 1 ,也就是说当事务提交时会调用 fsync 对 redo log 进行刷盘
另外,InnoDB 存储引擎有一个后台线程,每隔1 秒,就会把 redo log buffer 中的内容写到文件系统缓存(page cache),然后调用 fsync 刷盘。
也就是说,一个没有提交事务的 redo log 记录,也可能会刷盘。 为什么呢? 因为在事务执行过程 redo log 记录是会写入redo log buffer 中,这些 redo log 记录会被后台线程刷盘。
除了后台线程每秒1次的轮询操作,还有一种情况,当 redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘。
下面是不同刷盘策略的流程: 1、innodb_flush_log_at_trx_commit=0
为0时,如果MySQL挂了或宕机可能会有1秒数据的丢失。
2、innodb_flush_log_at_trx_commit=1
为1时, 只要事务提交成功,redo log记录就一定在硬盘里,不会有任何数据丢失。
如果事务执行期间MySQL挂了或宕机,这部分日志丢了,但是事务并没有提交,所以日志丢了也不会有损失。
3、innodb_flush_log_at_trx_commit=2
为2时, 只要事务提交成功,redo log buffer中的内容只写入文件系统缓存(page cache)。
如果仅仅只是MySQL挂了不会有任何数据丢失,但是宕机可能会有1秒数据的丢失。
1.3 日志文件组
硬盘上存储的 redo log 日志文件不只一个,而是以一个日志文件组的形式出现的,每个的redo日志文件大小都是一样的。
比如可以配置为一组4个文件,每个文件的大小是 1GB,整个 redo log 日志文件组可以记录4G的内容(文件的大小和个数均可通过配置调整)。
它采用的是环形数组形式,从头开始写,写到末尾又回到头循环写,如下图所示。
在个日志文件组中还有两个重要的属性,分别是 write pos、checkpoint
。write pos 是当前记录的位置,一边写一边后移
。checkpoint 是当前要擦除的位置,也是往后推移
每次刷盘 redo log 记录到日志文件组中,write pos 位置就会后移更新。
每次 MySQL 加载日志文件组恢复数据时,会清空加载过的 redo log 记录,并把 checkpoint 后移更新。
write pos 和 checkpoint 之间的还空着的部分可以用来写入新的 redo log 记录。
如果 write pos 追上 checkpoint ,表示日志文件组满了,这时候不能再写入新的 redo log 记录,MySQL 得停下来,清空一些记录,把 checkpoint 推进一下。
1.4 redo log 小结
相信大家都知道 redo log 的作用和它的刷盘时机、存储形式。
现在我们来思考一个问题:只要每次把修改后的数据页直接刷盘不就好了,还有 redo log 什么事?它们不都是刷盘么?差别在哪里?
实际上,数据页(binlog)大小是16KB,刷盘比较耗时,可能就修改了数据页里的几 Byte 数据,有必要把完整的数据页刷盘吗?而且数据页刷盘是随机写,一个数据页对应的位置可能在硬盘文件的随机位置,所以写入性能是很差。
如果是写 redo log,一行记录可能就占几十 Byte,只包含表空间号、数据页号、磁盘文件偏移 量、更新值,再加上是顺序写,所以刷盘速度很快。
所以用 redo log 形式记录修改内容,性能会远远超过刷数据页的方式,这也让数据库的并发能力更强。
其实内存的数据页在一定时机也会刷盘,我们把这称为页合并,讲 Buffer Pool的时候会对这块细说
二、binlog
不管用什么存储引擎,只要发生了表数据更新,都会产生 binlog 日志。
那 binlog 到底是用来干嘛的?
可以说MySQL数据库的数据备份、主备、主主、主从都离不开binlog,需要依靠binlog来同步数据,保证数据一致性。
binlog会记录所有涉及更新数据的逻辑操作。
2.1 binlog与redo log的异同
。redo log 是物理日志,记录内容是“在某个数据页上做了什么修改”,属于 InnoDB 存储引擎。而 binlog 是逻辑日志,所有存储引擎共有,属于MySQL Server 层。 。redo log 是循环写的,空间固定会用完然后复写;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
2.2 记录格式
binlog 日志有三种格式,可以通过binlog_format参数指定:
。statement
。row
。mixed
指定statement,记录的内容是SQL语句原文,比如执行一条 update T set update_time=now() where id=1,记录的数据如下:
BEGIN -- 事务开始
user 库名;
update T set update_time=now()where id=1
COMMIT xid = xxx -- 提交事务与事务id
同步数据时,会执行记录的SQL语句,但是有个问题,update_time=now()这里会获取当前系统时间,直接执行会导致与原库的数据不一致。为了解决这种问题,我们需要将binlog_format参数指定为row,记录的内容不再是简单的SQL语句了,还包含操作的具体数据,记录内容如下。
row格式记录的内容看不到详细信息,要通过mysqlbinlog工具解析出来。
update_time=now()变成了具体的时间update_time=1627112756247,条件后面的@1、@2、@3 都是该行数据第 1 个~3 个字段的原始值(假设这张表只有 3 个字段)。这样就能保证同步数据的一致性,通常情况下都是指定为row,这样可以为数据库的恢复与同步带来更好的可靠性。
但是这种格式,需要更大的容量来记录,比较占用空间,恢复与同步时会更消耗IO资源,影响执行速度。所以就有了一种折中的方案,指定为mixed,记录的内容是前两者的混合。MySQL会判断这条SQL语句是否可能引起数据不一致,如果是,就用row格式,否则就用statement格式。
2.3写入机制
binlog的写入时机也非常简单,事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中。每次写入的最小单位都是16KB(对应page的大小),即使对应的16KB中只有个别数据发生了变化。
因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。可以通过binlog_cache_size参数控制单个线程 binlog cache 大小,如果存储内容超过了这个参数,就要暂存到磁盘(Swap)。
binlog日志刷盘流程如下:
SQL => 事务开始 => 写undo log并更新内存数据 => 写redo log并处于prepare状态 => 写binlog => 提交事务;redo log更新为commit状态 => 返回响应
。上图的 write,是指把日志写入到文件系统的 page cache,并没有把数据持久化到磁盘,所以速度比较快 。上图的 fsync,才是将数据持久化到磁盘的操作
write和fsync的时机,可以由参数sync_binlog控制,默认是0。为0的时候,表示每次提交事务都只write,由系统自行判断什么时候执行fsync。虽然性能得到提升,但是机器宕机,page cache里面的 binglog 会丢失。
为了安全起见,可以设置为1,表示每次提交事务都会执行fsync,就如同binlog 日志刷盘流程一样。
最后还有一种折中方式,可以设置为N(N>1),表示每次提交事务都write,但累积N个事务后才fsync。在出现IO瓶颈的场景里,将sync_binlog设置成一个比较大的值,可以提升性能。相对应的,如果机器宕机,会丢失最近N个事务的binlog日志。
2.4、日志的两阶段提交
redo log(重做日志)让InnoDB存储引擎拥有了崩溃恢复能力。binlog(归档日志)保证了MySQL集群架构的数据一致性。虽然它们都属于持久化的保证,但是侧重点不同。
在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的写入时机不一样。
redo log与binlog两份日志之间的逻辑不一致,会出现什么问题?
我们以update语句为例,假设id=2的记录,字段c值是0,把字段c值更新成1,SQL语句为update T set c=1 where id=2。假设执行过程中写完redo log日志后,binlog日志写期间发生了异常,会出现什么情况呢?
由于binlog没写完就异常,这时候binlog里面没有对应的修改记录。因此,之后用binlog日志恢复数据时,就会少这一次更新,恢复出来的这一行c值是0,而原库因为redo log日志恢复,这一行c值是1,最终数据不一致。
为了解决两份日志之间的逻辑一致问题,InnoDB存储引擎使用两阶段提交方案。
原理很简单,将redo log的写入拆成了 prepare和commit 两个步骤,这就是两阶段提交。
使用两阶段提交后,写入binlog时发生异常也不会有影响,因为MySQL根据redo log日志恢复数据时,发现redo log还处于prepare阶段,并且没有对应binlog日志,就会回滚该事务。
再看一个场景,redo log设置commit阶段发生异常,那会不会回滚事务呢?
并不会回滚事务,它会执行上图框住的逻辑,虽然redo log是处于prepare阶段,但是能通过事务id找到对应的binlog日志,所以MySQL认为是完整的,就会提交事务恢复数据。
三、undo log
我们知道如果想要保证事务的原子性,就需要在异常发生时,对已经执行的操作进行回滚,在 MySQL 中,恢复机制是通过 回滚日志(undo log) 实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后再执行相关的操作。如果执行过程中遇到异常的话,我们直接利用 回滚日志 中的信息将数据回滚到修改之前的样子即可!并且,回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚将之前未完成的事务。
另外,MVCC 的实现依赖于:隐藏字段( 6-byte DB_TRX_ID 、7-byte BD_ROLL_PTR、6-byte DB_ROW_ID)、Read View、undo log。在内部实现中,InnoDB 通过数据行的 DB_TRX_ID 和 Read View 来判断数据的可见性,如不可见,则通过数据行的 DB_ROLL_PTR 找到 undo log 中的历史版本。每个事务读到的数据版本可能是不一样的,在同一个事务中,用户只能看到该事务创建 Read View 之前已经提交的修改和该事务本身做的修改
四、总结
MySQL InnoDB 引擎使用 redo log(重做日志) 保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性。
MySQL数据库的数据备份、主备、主主、主从都离不开binlog,需要依靠binlog来同步数据,保证数据一致性。
五、日志题总结
5.1、MySQL 的 change buffer 是什么?
- 反过来,假设一个业务的更新模式是写入之后马上会做查询,那么即使满足了条件,将更新先记录在 change buffer,但之后由于马上要访问这个数据页,会立即触发 merge 过程。这样随机访问 IO 的次数不会减少,反而增加了 change buffer 的维护代价。
当需要更新一个数据页时,如果数据页在内存中就直接更新;而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中。
这样就不需要从磁盘中读入这个数据页了,在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。
注意唯一索引的更新就不能使用 change buffer,实际上也只有普通索引可以使用。
适用场景:
- 对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时 change buffer 的使用效果最好。 这种业务模型常见的就是账单类、日志类的系统。
5.2、MySQL 是如何判断一行扫描数的?
。MySQL 在真正开始执行语句之前,并不能精确地知道满足这个条件的记录有多少条。
。而只能根据统计信息来估算记录数。这个统计信息就是索引的“区分度。
5.3、MySQL 的 redo log 和 binlog 区别?
5.4、为什么需要 redo log?
。redo log 主要用于 MySQL 异常重启后的一种数据恢复手段,确保了数据的一致性。
。其实是为了配合 MySQL 的 WAL 机制。因为 MySQL 进行更新操作,为了能够快速响应,所以采用了异步写回磁盘的技术,写入内存后就返回。但是这样,会存在 crash后 内存数据丢失的隐患,而 redo log 具备 crash safe 的能力。
5.6、为什么 redo log 具有 crash-safe 的能力,是 binlog 无法替代的?
第一点:redo log 可确保 innoDB 判断哪些数据已经刷盘,哪些数据还没有
。redo log 和 binlog 有一个很大的区别就是,一个是循环写,一个是追加写。也就是说 redo log 只会记录未刷盘的日志,已经刷入磁盘的数据都会从 redo log 这个有限大小的日志文件里删除。binlog 是追加日志,保存的是全量的日志。
。当数据库 crash 后,想要恢复 未刷盘但已经写入 redo log 和 binlog 的数据 到内存时,binlog 是无法恢复的。虽然 binlog 拥有全量的日志,但没有一个标志让 innoDB 判断哪些数据已经刷盘,哪些数据还没有。
。但 redo log 不一样,只要刷入磁盘的数据,都会从 redo log 中抹掉,因为是循环写!数据库重启后,直接把 redo log 中的数据都恢复至内存就可以了。
第二点:如果 redo log 写入失败,说明此次操作失败,事务也不可能提交
。redo log 每次更新操作完成后,就一定会写入日志,如果 写入失败 ,说明此次操作失败,事务也不可能提交。
。redo log 内部结构是基于页的,记录了这个页的字段值变化,只要crash后读取redo log进行重放,就可以恢复数据。
这就是为什么 redo log 具有 crash-safe 的能力,而 binlog 不具备。
5.6、当数据库 crash 后,如何恢复未刷盘的数据到内存中?
根据 redo log 和 binlog 的两阶段提交,未持久化的数据分为几种情况:
。change buffer 写入,redo log 虽然做了 fsync 但未 commit,binlog 未 fsync 到磁盘,这部分数据丢失。
。change buffer 写入,redo log fsync 未 commit,binlog 已经 fsync 到磁盘,先从 binlog 恢复 redo log,再从 redo log 恢复 change buffer。
。change buffer 写入,redo log 和 binlog 都已经 fsync,直接从 redo log 里恢复。
5.7、redo log 写入方式?
redo log包括两部分内容,分别是内存中的 **日志缓冲 (redo log buffer)**和磁盘上的 日志文件 (redo log file)。
MySQL 每执行一条 DML 语句,会先把记录写入 redo log buffer(用户空间) ,再保存到内核空间的缓冲区 OS-buffer 中,后续某个时间点再一 次性将多个操作记录写到 redo log file(刷盘) 。这种先写日志,再写磁盘的技术,就是 WAL 。
可以发现,redo log buffer写入到redo log file,是经过OS buffer中转的。其实可以通过参数innodb_flush_log_at_trx_commit进行配置, 参数值含义如下:
0:称为 延迟写 ,事务提交时不会将redo log buffer中日志写入到OS buffer,而是每秒写入OS buffer并调用写入到redo log file中。
1:称为 实时写 ,实时刷”,事务每次提交都会将redo log buffer中的日志写入OS buffer并保存到redo log file中。
2:称为 实时写,延迟刷 。每次事务提交写入到OS buffer,然后是每秒将日志写入到redo log file。
5.8、redo log 的执行流程?
我们来看下Redo log的执行流程,假设执行的 SQL 如下:
update T set a =1 where id =666
。1、MySQL 客户端将请求语句 update T set a =1 where id =666,发往 MySQL Server 层。
。2、MySQL Server 层接收到 SQL 请求后,对其进行分析、优化、执行等处理工作,将生成的 SQL 执行计划发到 InnoDB 存储引擎层执行。
。3、InnoDB 存储引擎层将 a修改为1 的这个操作记录到内存中。
。4、记录到内存以后会修改 redo log 的记录,会在添加一行记录,其内容是 需要在哪个数据页上做什么修改 。
。5、此后,将事务的状态设置为 prepare ,说明已经准备好提交事务了。
。6、等到 MySQL Server 层处理完事务以后,会将事务的状态设置为 commit ,也就是提交该事务。
。7、在收到事务提交的请求以后, redo log 会把刚才写入内存中的操作记录写入到磁盘中,从而完成整个日志的记录过程。
5.9、binlog 的概念是什么,起到什么作用, 可以保证 crash-safe 吗?
。binlog 是归档日志,属于 MySQL Server 层的日志。可以实现 主从复制 和 数据恢复 两个作用。
。当需要 恢复数据 时,可以取出某个时间范围内的 binlog 进行重放恢复。
。但是 binlog 不可以做 crash safe,因为 crash 之前,binlog 可能没有写入完全 MySQL 就挂了。所以需要配合 redo log 才可以进行 crash safe。
5.10、什么是两阶段提交?
MySQL 将 redo log 的写入拆成了两个步骤:prepare 和 commit,中间再穿插写入binlog,这就是"两阶段提交"。
而两阶段提交就是让这两个状态保持逻辑上的一致。redolog 用于恢复主机故障时的未更新的物理数据,binlog 用于备份操作。两者本身就是两个独立的个体,要想 保持一致,就必须使用分布式事务的解决方案来处理。
为什么需要两阶段提交呢?
如果不用两阶段提交的话,可能会出现这样情况:
。1、先写 redo log,crash 后 bin log 备份恢复时少了一次更新,与当前数据不一致。
。2、先写 bin log,crash 后,由于 redo log 没写入,事务无效,所以后续 bin log 备份恢复时,数据不一致。
两阶段提交就是为了保证 redo log 和 binlog 数据的安全一致性。只有在这两个日志文件逻辑上高度一致了才能放心的使用。
在恢复数据时,redolog 状态为 commit 则说明 binlog 也成功,直接恢复数据;如果 redolog 是 prepare,则需要查询对应的 binlog事务是否成功,决定是 回滚还是执行。
5.11、MySQL 怎么知道 binlog 是完整的?
一个事务的 binlog 是有完整格式的:
statement 格式的 binlog,最后会有 COMMIT;
row 格式的 binlog,最后会有一个 XID event。
5.12、什么是 WAL 技术,有什么优点?
WAL,中文全称是 Write-Ahead Logging,它的关键点就是日志先写内存,再写磁盘。MySQL 执行更新操作后, 在真正把数据写入到磁盘前,先记录日志 。
好处是不用每一次操作都实时把数据写盘,就算 crash 后也可以通过redo log 恢复,所以能够实现快速响应 SQL 语句。
5.13、binlog 日志的三种格式
binlog 日志有三种格式
。1、Statement:基于SQL语句的复制((statement-based replication,SBR))
。2、Row:基于行的复制。(row-based replication,RBR)
。3、Mixed:混合模式复制。(mixed-based replication,MBR)
Statement格式
每一条会修改数据的 SQL 都会记录在 binlog 中
优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。
缺点:由于记录的只是执行语句,为了这些语句能在备库上正确运行,还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在备库得到和在主库端执行时 候相同的结果。
Row格式
不记录 SQL 语句上下文相关信息,仅保存哪条记录被修改。
优点:binlog 中可以不记录执行的 SQL 语句的上下文相关的信息,仅需要记录那一条记录被修改成什么了。所以rowlevel的日志内容会非常清楚的记录下每一行数 据修改的细节。不会出现某些特定情况下的存储过程、或 function、或trigger的调用和触发无法被正确复制的问题。
缺点:可能会产生大量的日志内容。
Mixed格式
实际上就是 Statement 与 Row 的结合。一般的语句修改使用 statment 格式保存 binlog,如一些函数,statement 无法完成主从复制的操作,则采用 row 格式保存 binlog,MySQL 会根据执行的每一条具体的 SQL 语句来区分对待记录的日志形式。
5.14、redo log日志格式
redo log buffer (内存中)是由首尾相连的四个文件组成的,它们分别是:ib_logfile_1、ib_logfile_2、ib_logfile_3、ib_logfile_4。
write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。
checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
write pos 和 checkpoint 之间的是“粉板”上还空着的部分,可以用来记录新的操作。
如果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。
有了 redo log,当数据库发生宕机重启后,可通过 redo log将未落盘的数据(check point之后的数据)恢复,保证已经提交的事务记录不会丢失, 这种能力称为 crash-safe 。
5.15、原本可以执行得很快的 SQL 语句,执行速度却比预期的慢很多,原因是什么?如何解决?
原因:从大到小可分为四种情况
1、MySQL 数据库本身被堵住了,比如:系统或网络资源不够。
2、SQL 语句被堵住了,比如:表锁,行锁等,导致存储引擎不执行对应的 SQL 语句。
3、确实是索引使用不当,没有走索引。
4、表中数据的特点导致的,走了索引,但回表次数庞大。
解决:
1、考虑采用 force index 强行选择一个索引
2、考虑修改语句,引导 MySQL 使用我们期望的索引。比如把“order by b limit 1” 改成 “order by b,a limit 1” ,语义的逻辑是相同的。
3、第三种方法是,在有些场景下,可以新建一个更合适的索引,来提供给优化器做选择,或删掉误用的索引。
4、如果确定是索引根本没必要,可以考虑删除索引。
5.16、InnoDB 数据页结构
一个数据页大致划分七个部分
1、File Header:表示页的一些通用信息,占固定的38字节。
2、page Header:表示数据页专有信息,占固定的56字节。
3、inimum+Supermum:两个虚拟的伪记录,分别表示页中的最小记录和最大记录,占固定的26字节。
4、User Records:真正存储我们插入的数据,大小不固定。
5、Free Space:页中尚未使用的部分,大小不固定。
6、Page Directory:页中某些记录的相对位置,也就是各个槽对应的记录在页面中的地址偏移量。
7、File Trailer:用于检验页是否完整,占固定大小 8 字节。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)