InnoDB引擎底层原理
2023-07-03 12:28:46   9  举报             
     
         
 InnoDB引擎底层原理
    作者其他创作
 大纲/内容
  InnoDB记录存储结构和索引页结构    
     InnoDB是一个将表中的数据存储到磁盘上的存储引擎,
  
     InnoDB如何获取记录    
     将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,InnoDB中页的大小一般为16 KB。也就是在一般情况下,一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。  
     行格式    
     我们可以在创建或修改表的语句中指定行格式:CREATE TABLE表名(列的信息) ROW_FORMAT=行格式名称  
     表中的某些列可能存储NULL值,Compact行格式把这些值为NULL的列统一管理起来,存储到 NULL 值列表每个允许存储 NULL 的列对应一个二进制位,二进制位的值为1时,代表该列的值为NULL。二进制位的值为0时,代表该列的值不为NULL。  
     记录头    
     预留位 1 1 没有使用  
     预留位 2 1 没有使用  
     delete_mask 1 标记该记录是否被删除  
     min_rec_mask 1 B+树的每层非叶子节点中的最小记录都会添加该标记  
     n_owned 4 表示当前记录拥有的记录数  
     heap_no 13 表示当前记录在页的位置信息  
     record_type 表示当前记录的类型    
     0 表示普通记录  
     1 表示 B+树非叶子节点记录  
     2 表示最小记录  
     3 表示最大记录  
     MySQL默认添加的隐藏列    
     DB_ROW_ID(row_id):非必须,6 字节,表示行 ID,唯一标识一条记录  
     DB_TRX_ID:必须,6 字节,表示事务 ID  
     DB_ROLL_PTR:必须,7 字节,表示回滚指针  
     InnoDB 表对主键的生成策略           
     优先使用用户自定义主键作为主键,如果用户没有定义主键,则选取一个 Unique 键作为主键,如果表中连 Unique 键都没有
定义的话,则 InnoDB 会为表默认添加一个名为 row_id 的隐藏列作为主键。DB_TRX_ID(也可以称为 trx_id) 和 DB_ROLL_PTR(也可以称为 roll_ptr) 这两个列是必有的,但是 row_id 是可选的(在没有自定义主键以及 Unique 键的情况下才会添加该列)。
    定义的话,则 InnoDB 会为表默认添加一个名为 row_id 的隐藏列作为主键。DB_TRX_ID(也可以称为 trx_id) 和 DB_ROLL_PTR(也可以称为 roll_ptr) 这两个列是必有的,但是 row_id 是可选的(在没有自定义主键以及 Unique 键的情况下才会添加该列)。
 索引页格式    
     索引页是InnoDB 管理存储空间的基本单位,一个页的大小一般是 16KB。  
     一个 InnoDB 数据页的存储空间大致被划分成了 7 个部分:    
     File Header 文件头部 38 字节 页的一些通用信息  
     Page Header 页面头部 56 字节 数据页专有的一些信息  
     Infimum + Supremum 最小记录和最大记录 26 字节 两个虚拟的行记录  
     User Records 用户记录 大小不确定 实际存储的行记录内容    
     我们自己存储的记录会按照我们指定的行格式存储到 User Records 部分  
     Free Space 空闲空间 大小不确定 页中尚未使用的空间  
     Page Directory 页面目录 大小不确定 页中的某些记录的相对位置    
     Page Directory 主要是解决记录链表的查找问题  
     File Trailer 文件尾部 8 字节 校验页是否完整  
     InnoDB 的体系结构    
     宏观的角度看看 InnoDB 的内存结构和磁盘存储结构。MySQL官网原图  
     独立表空间结构    
     对于 16KB 的页来说,连续的64 个页就是一个区,也就是说一个区默认占用 1MB 空间大小  
     不论是系统表空间还是独立表空间,都可以看成是由若干个区组成的,每 256个区又被划分成一个组  
     一个索引会生成 2 个段,一个叶子节点段,一个非叶子节点段。段其实不对应表空间中某一个连续的物理区域,而是一个逻辑上的概念  
     引入区的主要目的是什么    
     我们每向表中插入一条记录,本质上就是向该表的聚簇索引以及所有二级索引代表的 B+树的节点中插入数据。而 B+树的每一层中的页都会形成一个双向链表,如果是以页为单位来分配存储空间的话,双向链表相邻的两个页之间的物理位置可能离得非常远。  
     系统表空间    
     Innodb三大特性    
     双写缓冲区/双写机制  
     Buffer Pool  
     自适应 Hash 索引  
     doublewrite buffer 的作用    
     提高 innodb 把缓存的数据写到硬盘这个过程的安全性  
     innodb 的事务日志不需要包含所有数据的前后映像,而是二进制变化量,这可以节省大量的 IO  
     InnoDB 的 Buffer Pool    
     缓存的重要性    
     减少磁盘IO的开销  
     Buffer Pool    
     InnoDB 为了缓存磁盘中的页,在 MySQL 服务器启动的时候就向操作系统申请了一片连续的内存默认128m    
     查看buffer大小  show variables like 'innodb_buffer_pool_size';  
     配置buffer的值  innodb_buffer_pool_size = 268435456    
     268435456 的单位是字节,也就是指定 Buffer Pool 的大小为 256M。需要注意的是,Buffer Pool 也不能太小,最小值为 5M(当小于该值时会自动设置成5M)。  
     Buffer Pool 内部组成  
     free 链表的管理  
     缓存页的哈希处理    
     根据表空间号 + 页号来定位一个页的,也就相当于表空间号 +页号是一个 key,缓存页就是对应的 value  
     用表空间号 + 页号作为 key,缓存页作为 value 创建一个哈希表,在需要访问某个页的数据时,先从哈希表中根据表空间号 + 页号看看有没有对应的缓存页,如果有,直接使用该缓存页就好,如果没有,那就从 free 链表中选一个空闲的缓存页,然后把磁盘中对应的页加载到该缓存页的位置。、  
     LRU 链表的管理  
     刷新脏页到磁盘    
     从 LRU 链表的冷数据中刷新一部分页面到磁盘  
     从 flush 链表中刷新一部分页面到磁盘  
     多个 Buffer Pool 实例    
     通过设置 innodb_buffer_pool_instances 的值来修改 Buffer Pool 实例的个数  
     每个 Buffer Pool 实例实际占多少内存空间    
     使用这个公式算出来的:innodb_buffer_pool_size/innodb_buffer_pool_instances  
     InnoDB 规定:innodb_buffer_pool_instances 能设置的最大值是 64,而且当 innodb_buffer_pool_size(默认 128M)的值小于 1G 的时候设置多个实例是无效的,InnoDB 会默认把 innodb_buffer_pool_instances 的值修改为 1。  
     最佳的 innodb_buffer_pool_instances 的数量是,innodb_buffer_pool_size 除以 innodb_buffer_pool_instances,可以让每个 BufferPool 实例达到 1 个 G  
     查看 Buffer Pool 的状态信息    
     SHOW ENGINE INNODB STATUS\G    
     Total memory allocated:代表 Buffer Pool 向操作系统申请的连续内存空间大小,包括全部控制块、缓存页、以及碎片的大小。  
     Dictionary memory allocated:为数据字典信息分配的内存空间大小,注意这个内存空间和 Buffer Pool 没啥关系,不包括在 Total memory allocated 中  
     Buffer pool size:代表该 Buffer Pool 可以容纳多少缓存页,注意,单位是页!  
     Free buffers:代表当前 Buffer Pool 还有多少空闲缓存页,也就是 free 链表中还有多少个节点。  
     Database pages:代表 LRU 链表中的页的数量,包含 young 和 old 两个区域的数量。  
     Old database pages:代表 LRU 链表 old 区域的节点数量  
     Modified db pages:代表脏页数量,也就是 flush 链表中节点的数量  
     Pending reads:正在等待从磁盘上加载到 Buffer Pool 中的页面数量  
     Pending writes LRU:即将从 LRU 链表中刷新到磁盘中的页面数量。  
     Pending writes flush list:即将从 flush 链表中刷新到磁盘中的页面数量。  
     Pending writes single page:即将以单个页面的形式刷新到磁盘中的页面数量  
     Pages made young:代表 LRU 链表中曾经从 old 区域移动到 young 区域头部的节点数量。  
     Page made not young:在将 innodb_old_blocks_time 设置的值大于 0 时,首次访问或者后续访问某个处在old 区域的节点时由于不符合时间间隔的限制而不能将其移动到 young 区域头部时,Page made not young 的值会加 1。  
     youngs/s:代表每秒从 old 区域被移动到 young 区域头部的节点数量  
     non-youngs/s:代表每秒由于不满足时间限制而不能从 old 区域移动到 young区域头部的节点数量。  
     Pages read、created、written:代表读取,创建,写入了多少页。后边跟着读取、创建、写入的速率。  
     Buffer pool hit rate:表示在过去某段时间,平均访问 1000 次页面,有多少次该页面已经被缓存到 Buffer Pool 了。  
     young-making rate:表示在过去某段时间,平均访问 1000 次页面,有多少次访问使页面移动到 young 区域的头部了。  
     not (young-making rate):表示在过去某段时间,平均访问 1000 次页面,有多少次访问没有使页面移动到 young 区域的头部。  
     LRU len:代表 LRU 链表中节点的数量。  
     unzip_LRU:代表 unzip_LRU 链表中节点的数量。  
     I/O sum:最近 50s 读取磁盘页的总数。  
     I/O cur:现在正在读取的磁盘页数量。  
     I/O unzip sum:最近 50s 解压的页面数量。  
     I/O unzip cur:正在解压的页面数量。  
    
 
 
 
 
  0 条评论
 下一页