Mysql InnoDB存储引擎

Mysql整体架构

Mysql存储引擎对比

InnoDB架构

内存结构

Buffer Pool

缓冲池是主内存中的一个区域,InnoDB在访问表和索引数据时会在该区域进行缓存。缓冲池允许直接从内存访问频繁使用的数据,这加快了处理速度。在专用服务器上,通常会将高达80%的物理内存分配给缓冲池。

为了提高高容量读取操作的效率,缓冲池被划分为可能容纳多行的页面。为了提高缓存管理的效率,缓冲池被实现为页面的链表;很少使用的数据使用最近最少使用(LRU)算法的变体从高速缓存中老化。

了解如何利用缓冲池将频繁访问的数据保存在内存中是MySQL调优的一个重要方面。

使用LRU算法的变体将缓冲池作为列表进行管理。当需要空间将新页面添加到缓冲池时,会收回最近使用最少的页面,并将新页面增加到列表的中间。此中点插入策略将列表视为两个子列表:

在Head,最近访问的新(“年轻”)页面的子列表

在Tail,最近访问次数较少的旧页面的子列表。

Buffer Pool List

该算法将频繁使用的页面保留在新的子列表中。旧的子列表包含不太频繁使用的页面;这些页面可能会被驱逐。

默认情况下,算法操作如下:

缓冲池的3/8用于旧的子列表。

列表的中点是新子列表的尾部与旧子列表的头部相交的边界。

当InnoDB将一个页面读取到缓冲池中时,它最初会将其插入中点(旧子列表的头)。可以读取页面,因为它是用户启动的操作(如SQL查询)所必需的,或者是InnoDB自动执行的预读操作的一部分。

访问旧子列表中的页面会使其“年轻”,并将其移动到新子列表的头部。如果由于用户启动的操作需要读取页面,则会立即进行第一次访问,并使页面年轻。如果页面是由于预读操作而读取的,则第一次访问不会立即发生,而且可能在页面被收回之前根本不会发生。

当数据库运行时,缓冲池中未被访问的页面会向列表的尾部移动,从而“老化”。新旧子列表中的页面都会随着其他页面的更新而老化。旧子列表中的页面也会随着页面插入中点而老化。最终,一个未使用的页面到达旧子列表的尾部并被逐出。

read-ahead operation(预读操作)是一种优化技术,用于提高数据访问的性能。当InnoDB预见到某个数据页(通常是一个索引页或一个数据页)可能会被访问时,它会主动提前从磁盘上读取该数据页到Buffer Pool中。

默认情况下,查询读取的页面会立即移动到新的子列表中,这意味着它们在缓冲池中停留的时间更长。例如,为mysqldump操作或不带WHERE子句的SELECT语句执行的表扫描可以将大量数据带入缓冲池,并收回等量的旧数据,即使新数据再也不用了。类似地,由预读后台线程加载并只访问一次的页面会移动到新列表的开头。这些情况可能会将经常使用的页面推送到旧的子列表中,在那里它们会被驱逐。

Change Buffer

Change Buffer是一种特殊的数据结构,当二级索引页不在缓冲池中时,它会缓存对这些页的更改。缓冲的更改可能由INSERT、UPDATE或DELETE操作(DML)引起,稍后当页面通过其他读取操作加载到缓冲池中时,这些更改将被合并

在表上执行INSERT、UPDATE和DELETE操作时,辅助索引列的值通常按未排序的顺序排列,需要大量I/O才能使辅助索引保持最新。当相关页面不在缓冲池中时,Change Buffer缓存对辅助索引项的更改,从而避免了昂贵的I/O操作,因为不会立即从磁盘读取页面。当页面加载到缓冲池中时,Change Buffer会合并,更新后的页面稍后会刷新到磁盘当服务器接近空闲时,以及在缓慢关闭期间,InnoDB主线程合并缓冲的更改。

在系统大部分空闲或缓慢关闭时运行的清除操作会定期将更新的索引页写入磁盘。与立即将每个值写入磁盘相比,清除操作可以更有效地写入一系列索引值的磁盘块。

在内存中,Change Buffer占据了缓冲池的一部分,默认25%。

Adaptive Hash Index

自适应哈希索引使InnoDB能够在具有适当的工作负载组合和足够的缓冲池内存的系统上执行更像内存中的数据库,而不会牺牲事务特性或可靠性。自适应哈希索引由innodb_adaptive_hash_index变量启用,或在服务器启动时由--skip innodb自适应哈希索引关闭。

根据观察到的搜索模式,使用索引键的前缀构建哈希索引。前缀可以是任何长度,并且可能只有B树中的一些值出现在哈希索引中。哈希索引是根据经常访问的索引页的需要构建的。

如果一个表几乎完全适合主内存,那么哈希索引可以通过直接查找任何元素来加快查询速度,将索引值变成某种指针。InnoDB有一个监视索引搜索的机制。如果InnoDB注意到查询可以从构建哈希索引中受益,它会自动这样做。

对于某些工作负载,哈希索引查找的速度大大超过了监视索引查找和维护哈希索引结构的额外工作。在繁重的工作负载(例如多个并发联接)下,对自适应哈希索引的访问有时会成为争用的来源。使用LIKE运算符和%通配符的查询也往往没有好处。对于没有从自适应哈希索引中获益的工作负载,关闭它可以减少不必要的性能开销。由于很难提前预测自适应哈希索引是否适用于特定的系统和工作负载,请考虑在启用和禁用它的情况下运行基准测试。

对自适应哈希索引功能进行了分区。每个索引都绑定到一个特定的分区,每个分区都由一个单独的锁存器保护。分区由innodb_adaptive_hash_index_parts变量控制。innodb_adaptive_hash_index_parts变量默认设置为8。最大设置为512。

您可以在SHOW ENGINE INNODB STATUS输出的SEMAPHORES部分中监视自适应哈希索引的使用和争用。如果在btr0sea.c中创建的rw锁存器上有许多线程在等待,请考虑增加自适应哈希索引分区的数量或禁用自适应哈希索引。

Log Buffer

日志缓冲区是存储要写入磁盘上日志文件的数据的内存区域。日志缓冲区大小由innodb_Log_buffer_size变量定义。默认大小为16MB。日志缓冲区的内容会定期刷新到磁盘。如果有更新、插入或删除许多行的事务,那么增加日志缓冲区的大小可以节省磁盘I/O。

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

磁盘结构

Doublewrite Buffer

双写缓冲区是一个存储区域,在将页面写入InnoDB数据文件中的适当位置之前,InnoDB会在其中写入从缓冲池中刷新的页面。如果在页面写入过程中出现操作系统、存储子系统或意外的mysqld进程退出,InnoDB可以在崩溃恢复期间从doublewrite缓冲区中找到页面的良好副本。

尽管数据写入两次,但双写缓冲区不需要两倍的I/O开销或两倍的输入/输出操作。通过对操作系统的单个fsync()调用,将数据写入大的顺序块中的双写缓冲区(innodb_flush_method设置为O_DIRECT_NO_fsync的情况除外)。

Redo Log

重做日志是一种基于磁盘的数据结构,在崩溃恢复期间用于更正由不完整事务写入的数据。在正常操作过程中,重做日志对SQL语句或低级API调用产生的更改表数据的请求进行编码。在初始化期间和接受连接之前,未在意外关闭之前完成更新数据文件的修改将自动重播。

重做日志在磁盘上由重做日志文件物理表示。写入重做日志文件的数据是根据受影响的记录进行编码的,这些数据统称为重做。通过重做日志文件的数据传输由不断增加的LSN值表示。重做日志数据会随着数据修改的进行而附加,最旧的数据会随着检查点的进行而截断。

Undo Logs

撤消日志是与单个读写事务相关联的撤消日志记录的集合。撤消日志记录包含有关如何撤消事务对聚集索引记录的最新更改的信息。如果另一个事务需要将原始数据作为一致读取操作的一部分来查看,则会从撤消日志记录中检索未修改的数据。撤消日志存在于撤消日志段中,而撤消日志段包含在回滚段中。回滚段位于撤消表空间和全局临时表空间中。

位于全局临时表空间中的撤消日志用于修改用户定义的临时表中的数据的事务。这些撤消日志不会被重新记录,因为它们不是崩溃恢复所必需的。它们仅用于服务器运行时的回滚。这种类型的撤消日志避免了重做日志I/O,从而提高了性能。

锁和事务

MVCC

Multi-Version Concurrency Control 多版本并发控制,是一致性非锁定读。

在mysql中常见的 select .... from where ...  不加锁。

MVCC 读取的是快照视图,不需要等待X锁的释放,也不加锁,不影响X锁的获取。

MVCC只在READ COMMITTD 、REPEATABLE READ 这两种隔离级别下起作用,因为另2种隔离级别不需要用到。

MVCC在READ COMMITTD 、REPEATABLE READ 这两个隔离级别的一个很大不同是:生成ReadView的时机不同,READ COMMITTD在每一次进行普通SELECT操作前都会生成一个ReadView,而REPEATABLE READ只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复使用这个ReadView就好了。

共享和互斥锁

InnoDB实现了标准的行级锁定,其中有两种类型的锁,共享(S)锁和独占(X)锁。

共享(S)锁允许持有该锁的事务读取一行。

排他(X)锁允许持有该锁的事务更新或删除行。

如果事务T1在行r上持有共享(S)锁,则来自某个不同事务T2的对行r上的锁的请求被如下处理:

T2对S锁的请求可以被立即批准。结果,T1和T2都在r上保持S锁。

不能立即批准T2对X锁的请求。

如果事务T1在行r上持有排他(X)锁,则不能立即批准来自某个不同事务T2的对r上任一类型锁的请求。相反,事务T2必须等待事务T1释放其对行r的锁定。

加锁是一致性锁定读,FOR UPDATE 读加X锁,但允许一致性非锁定读;FOR SHARE 读加S锁(与X锁互斥)。

意向锁

InnoDB支持多粒度锁定,允许行锁和表锁共存。

考虑这样一种场景,一张表中有几千万条数据,场景需要对整个表加X锁,因此在加上表X锁前引擎需要检查该表是否已存在某个行X锁(因为表与行的X锁也是互斥),这样就需要遍历整个表的每个行是否有上锁,效率极差。

因此Mysql的专家们发明了IS和IX意向锁,意向锁是表级别的,每当有行S或X锁时都会在表上一个IS或IX锁表示该表正在使用相应的锁,这样当需要对表级别上锁时就不需要遍历整个表的行锁了,只需要检查该表是否有意向锁即可。

总结:IS、IX锁是表级锁,它们的提出仅仅为了在之后加表级别的S锁和X锁时可以快速判断表中的记录是否被上锁,以避免用遍历的方式来查看表中有没有上锁的记录,也就是说其实IS锁和IX锁是兼容的,IX锁和IX锁是兼容的。

XIXSIS
XConflictConflictConflictConflict
IXConflictCompatibleConflictCompatible
SConflictConflictCompatibleCompatible
ISConflictCompatibleCompatibleCompatible

Record Locks

准确的对一行数据加锁,例如

select ... from ... where id = ? for update

update ... where id = ?

Gap Locks

间隙锁定范围行数据,间隙锁是性能和并发性之间权衡的一部分。

例如有这样一张表hero

+--------+------------+---------+
| number | name | country |
+--------+------------+---------+
| 1 | l刘备 | 蜀 |
| 3 | z诸葛亮 | 蜀 |
| 8 | c曹操 | 魏 |
| 15 | x荀彧 | 魏 |
| 20 | s孙权 | 吴 |
+--------+------------+---------+

执行范围更新 update ... where id > 3 and id < 20

将会使用Gap Locks把(3,20)区间作为间隙锁,防止这个期间有例如id=4这样的数据插入。

试想如果使用Record Locks就很难实现良好的性能。

Gap Locks没有共享和互斥之分,它们唯一目的是防止其他事务插入数据到Gap中。

所以间隙锁不会限制其他事务对这条记录加Record Locks或者加Gap Locks。

Next-Key Locks

既要锁定一行数据,又要防止其他事务在该数据前面的间隙插入数据,

它是Record Locks + Gap Locks的组合。

Insert Intention Locks

事务在插入一条记录时需要判断一下插入位置是不是被别的事务加了所谓的gap锁,如果有的话,插入操作需要等待,直到拥有gap锁的那个事务提交。

插入意向锁作用是在等待的时候也需要在内存中生成一个锁结构,表明有事务想在某个间隙中插入新记录,但是现在在等待。

AUTO-INC锁

该锁的目的是自动给AUTO_INCREMENT 修饰的列递增赋值。

方式一 采用AUTO-INC锁,也就是在执行插入语句时就在表级别加一个AUTO-INC 锁,然后为每条待插入记录的AUTO_INCREMENT 修饰的列分配递增的值,在该语句执行结束后,再把AUTO-INC 锁释放掉。这样一个事务在持有AUTO-INC 锁的过程中,其他事务的插入语句都要被阻塞,可以保证一个语句中分配的递增值是连续的。
如果我们的插入语句在执行前不可以确定具体要插入多少条记录(无法预计即将插入记录的数量),比方说使用INSERT ... SELECT 、REPLACE ... SELECT 或者LOAD DATA 这种插入语句,一般是使用AUTO-INC 锁为AUTO_INCREMENT 修饰的列生成对应的值。

方式二 采用轻量级锁,在为插入语句生成AUTO_INCREMENT 修饰的列的值时获取一下这个轻量级锁,然后生成本次插入语句需要用到的AUTO_INCREMENT 列的值之后,就把该轻量级锁释放掉,并不需要等到整个插入语句执行完才释放锁。
如果我们的插入语句在执行前就可以确定具体要插入多少条记录,比方说我们上边举的关于表t 的例子中,在语句执行前就可以确定要插入2条记录,那么一般采用轻量级锁的方式对AUTO_INCREMENT 修饰的列进行赋值。这种方式可以避免锁定表,可以提升插入性能。

InnoDB提供了一个称之为innodb_autoinc_lock_mode的系统变量来控制到底使用上
述两种方式中的哪种来为AUTO_INCREMENT修饰的列进行赋值,当innodb_autoinc_lock_mode值为0时,一律采用AUTO-INC锁;当innodb_autoinc_lock_mode值为2时,一律采用轻量级锁;当
innodb_autoinc_lock_mode值为1时,两种方式混着来(也就是在插入记录数量确定时采用轻
量级锁,不确定时使用AUTO-INC锁)。不过当innodb_autoinc_lock_mode值为2时,可能会造
成不同事务中的插入语句为AUTO_INCREMENT修饰的列生成的值是交叉的,在有主从复制的场景中是不安全的。

默认innodb_autoinc_lock_mode值是1。

CRUD与锁

insert时的锁:

2个事务若insert的主键相同,后进的事务会X锁等待然后报出主键冲突;主键值不相同则互不影响,不需要等待

2个事务若insert的表有唯一索引,后进的事务会X锁等待,无论值是否相同都会X锁等待

begin ;

start TRANSACTION;

insert into rvdc_destination value (1000,'abc','2019-11-06 16:13:20');

commit;

数据页

将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,InnoDB中页的大小
一般为 16 KB。

行格式

4种不同类型的行格式,分别是Compact 、Redundant 、Dynamic 和Compressed 行格式。

可以使用以下语句来指定和修改行格式。

CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称
ALTER TABLE 表名 ROW_FORMAT=行格式名称

可以使用以下语句查看正在使用的行格式,默认是Dynamic。

SELECT TABLE_NAME, ROW_FORMAT   
FROM information_schema.TABLES   
WHERE TABLE_SCHEMA = '你的database'   
AND TABLE_NAME = '你的table';

记录头

由固定的5个字节组成,也就是40个二进制位,不同的位代表不同的意思

名称大小(bit)描述
预留位11没有使用
预留位11没有使用
delete_mask1标记该记录是否被删除
min_rec_mask1B+树的每层非叶子节点中的最小记录都会添加该标记
n_owned4行分组中该组中有多少条记录
heap_no13表示当前记录在记录堆的位置信息
record_type3表示当前记录的类型, 0 表示普通记录, 1 表示B+树非叶子节点记录, 2 表示页中最小记录, 3
表示页中最大记录
next_record16表示下一条记录的相对位置

行溢出

因为一个页的大小一般是16KB ,也就是16384 字节,而一个VARCHAR(M) 、text、blob所需要的空间超过一个页的大小,这种时候Dynamic行格式会把这一行的数据存储到其他页中,而真实记录中只存放其他页的地址。

数据页格式

名称大小(字节)描述
File Header38页文件的通用信息
Page Header56数据页的专有信息
Infimum + Supremum26最小记录和最大记录,两个虚拟的行记录
User Records不确定实际的行记录
Free Space不确定页中未使用的空闲空间
Page Directory不确定页中的某些记录的相对位置
File Trailer8校验页是否完整

 Infimum + Supremum 和 User Records

行数据的next_record 它表示从当前记录的真实数据到下一条记录的真实数据的地址偏移量,比方说第一条记录的next_record 值为32 ,意味着从第一条记录的真实数据的地址处向后找32 个字节便是下一条记录的真实数据。这其实是个链表,可以通过一条记录找到它的下一条记录。但是需要注意, 下一条记录指得并不是按照我们插入顺序的下一条记录,而是按照主键值由小到大的顺序的下一条记录。而且规定 Infimum记录(也就是最小记录) 的下一条记录就是本页中主键值最小的用户记录,而本页中主键值最大的用户记录的下一条记录就是 Supremum记录(也就是最大记录) 。

File Header 中有2个重要信息 FIL_PAGE_PREV 和FIL_PAGE_NEXT,分别代表本页的上一个和下一个页的页号,这样通过建立一个双向链表把许多的页就都串联起来了,而无需这些页在物理上真正连着。所以所有的数据页其实是一个双链表。

页分裂

假设已有这样一页数据,这页只能放下这3条数据,现在我们再插入一条(4, 4, 'a')的数据。

因为页10 最多只能放3条记录,所以我们不得不再分配一个新页。因为主键4<5,需要把主键值为5 的记录移动到页28 中

然后再把主键值为4 的记录插入到页10 中。

这个过程表明了在对页中的记录进行增删改操作的过程中,必须通过一些诸如记录移动的操作来始终保证下一个数据页中用户记录的主键值必须大于上一个页中用户记录的主键值。这个过程称为页分裂。
 

索引页

无索引

假如没有索引

那么在一个页中根据主键查询1条数据,可以使用 页目录(上面说过的主键链表) 的二分法进行快速查找。如果查询条件不是主键,则需要逐条遍历匹配。

如果在很多页中查找,无论是根据主键还是其他列都不能很快定位到记录所在的页,效率都很低。

简单索引

所以索引页的作用是帮助快速查找,是一个索引目录页。

索引页复用了数据页的结构,但只需要存放 主键 和 页号 2个列,然后为了跟用户记录能做区分,在记录头的 record_type 设置值为1,而用户记录该值为0。

现在如果查询主键=20的记录时,先到索引页30 中通过二分法快速定位到对应目录项,因为12 < 20 < 209 ,所以定位到对应的记录所在的页就是页9 ,再到存储用户记录的页9 中根据二分法快速定位到主键值为20 的用户记录。

B+树

虽然说目录项记录中只存储主键值和对应的页号,比用户记录需要的存储空间小多了,但是一个页
只有16KB 大小,能存放的目录项记录也是有限的,因此当现有的索引页放不下时会创建新的索引页。例如再插入一条主键是320的数据,过程是这样的

现在如果查询主键=20的记录时,因为索引页不止1个,需要先定位到对应的索引页,也就是页30,然后再定位到数据页和数据。

照这样的方式进行,实际上InnoDB的索引形态就会是这样

就是一棵B+树,实际用户记录其实都存放在B+树的最底层的节点上,这些节点也被称为叶子节点,其余用来存放目录项的节点称为非叶子节点,最上边的那个节点称为根节点。

这棵B+树有以下重要特性:

#页内的记录按照主键的大小顺序排成一个单向链表。

#同一层次的页与页之间(无论是数据页还是索引页)也按照主键大小顺序排成一个双向链表。

#叶子节点存储的是完整的用户记录。

二级索引

上面的B+树是主键的,而二级索引也是这样的方式,每一个二级索引再建一棵B+树,比如有一张表c1是int主键,c2是int二级索引

二级索引树跟主键B+树有一些不同:

#页内记录按照二级索引列进行大小排序成一个单向链表。

#同一层次的页与页之间(无论是数据页还是索引页)也按照二级索引列大小顺序排成一个双向链表。

#叶子节点也就是数据页只包含二级索引列和主键列。

以查找c2=4进行查询为例,过程会是这样:

1. 根据根页,也就是页44 ,可以快速定位到目录项记录所在的页为页42 (因为2 < 4 < 9 )。
2. 在页42 中可以快速定位到实际存储用户记录的页,但是由于c2 列并没有唯一性约束,所以c2 列值为4 的记录可能分布在多个数据页中,又因为2 < 4 ≤ 4 ,所以确定实际存储用户记录的页在页34 和页35 中。
3. 到页34 和页35 中定位到具体的记录。
4. 但是这个B+ 树的叶子节点中的记录只存储了c2 和c1 (也就是主键)两个列,所以我们必须再根据主键值去主键索引中再查找一遍完整的用户记录,这个过程叫回表。

所以一张表中每多一个二级索引,就需要多一个二级索引的数据页和索引页,来组成二级索引B+树。

联合索引

联合索引就跟二级索引的方式几乎一样了,本质上也是二级索引,比如有一张表c1是int主键,c2是int,c3是char,c2和c3是联合索引。

c2和c3列组合起来形成一个二级索引,排序方式先按c2,如果c2值相同再按c3排序。

在查找时必须先按c2查找,如果发现c2有值相同的,再按c3查找(如果c3也作为查询条件的话),这就是为什么联合索引必须要最左列匹配才能命中的原因。

性能最佳实践

设计

#主键尽可能保证递增方式,这样能顺序的插入数据页,否则插入时页已满会导致页分裂移动数据。

#创建索引要考虑列的基数,基数小(像boolean、枚举)的列使用索引匹配后还有大量数据,效果不好。

#较长的varchar列建索引考虑用前缀例如20个长度建索引,大部分情况下20个字符足以区分,例如idx_order_id (order_id(20))。

#避免建重复索引,例如

KEY idx_name_birthday_phone_number (name(10), birthday, phone_number),
KEY idx_name (name(10))

使用

#联合索引要最左列匹配,否则无法命中。

#联合索引的排序和group by要按索引顺序,且不能asc desc混用,否则失效。

#模糊查询要以列前缀进行匹配,否则失效。

#索引列不要参与函数表达式,否则失效,例如 WHERE my_col * 2 < 4。

#查询带出的列尽量在索引中已包含,避免回表。

#避免全表或大量数据的扫描,因为这会导致Buffer Pool中有用的缓存数据被大量淘汰替换,大大降低缓存命中率。

语句优化

访问方法分类

const 通过主键或唯一二级索引查询时,能够以极快的速度定位到唯一的记录。

ref 通过二级索引或以IS NULL查唯一二级索引时,由于结果集是一批数据需要回表但效率还是很高的。

ref_or_null 通过二级索引或IS NULL为条件时,例如key1 = 'abc' OR key1 IS NULL,效率与ref差不多。

range 对索引进行范围条件查询,例如key2 IN (1438, 6328) OR (key2 >= 38 AND key2 <= 79),包括主键范围查询,该结果集是个范围相对较大,因此效率比ref一般要差。

index 查询带出的字段在联合索引中全部包含,且查询条件在联合索引中但无法命中索引,例如有KEY idx_key_part(key_part1, key_part2, key_part3)三个字段的联合索引,SELECT key_part1, key_part2, key_part3 FROM single_table WHERE key_part2 = 'abc'; 这种情况下在查询优化器的识别下只要遍历这个联合索引的B+树叶子节点进行条件匹配就可以了。由于二级索引的数据体积比主键索引小,而且不需要回表,因此比直接遍历主键索引成本要小。

all 全表扫描主键索引。

eq_ref 连接查询中对被驱动表使用主键值或者唯一二级索引列的值进行等值查找,这种join查询也是非常快,例如 t1 join t2 on t1.t2_id = t2.id。

引擎观察语句

-- innodb引擎版本
show VARIABLES like 'innodb_version'
-- io线程数
show VARIABLES like 'innodb_%io_threads%'
-- purge线程数
show VARIABLES like 'innodb_purge_threads'

-- 每页大小
show status like 'innodb_page_size';
-- 缓冲池大小
show VARIABLES like 'innodb_buffer_pool_size'
-- 缓冲池实例数
show VARIABLES like 'innodb_buffer_pool_instances'

redo 缓冲池大小
show VARIABLES like 'innodb_log_buffer_size'
-- 新读取到的页插入到LRU列表尾端的N%处
show VARIABLES like 'innodb_old_blocks_pct'
-- 页读取到mid位置后需要等待多久才会被加入到LRU列表的热端
show VARIABLES like 'innodb_old_blocks_time'

-- 总体概览
show engine innodb status
Free buffers 表示当前Free列表中页的数量
Database pages 表示LRU列表中页的数量,可能的情况是Free buffers和Database pages的数量之和不等于Buffer pool size(缓冲池),因为缓冲池中的页还可能分配给自适应hash索引、lock信息、Insert Buffer等
Modified db pages 表示脏页列表(数据被修改需要刷入磁盘的页)
Buffer pool hit rate 997 / 1000 表示缓冲池的命中率,越高越好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值