tmp
innodb的物理文件:
1、B-tree管理
2、页面大小固定=16K
从物理文件的分类来看,有日志文件、主系统表空间文件ibdata、undo tablespace文件、临时表空间文件、用户表空间。我们这里主要关心存储用户数据的用户表空间的物理文件结构。用户表空间,顾名思义,就是用户创建的表空间,如果开启独立表空间参数,那么一个表空间会对应磁盘上的一个物理文件。
从外部来看,表空间是由连续的固定大小page构成。其实表空间文件内部还是组织为更复杂的逻辑结构,自顶向下可分为segment、extent和page。
page则是表空间数据存储的基本单位,innodb将表文件(xxx.ibd)按page切分,依类型不同,page内容也有所区别,最为常见的是存储数据库表的行记录。
page=16K extent=64page=1M segment= N extent index=2segment tablespace=N segement
表空间下一级称为segment。segment与数据库中的索引相映射。Innodb引擎内,每个索引对应两个segment:管理叶子节点的segment和管理非叶子节点segment。创建索引中很关键的步骤便是分配segment,Innodb内部使用INODE来描述segment。
每个独立表空间都对应磁盘上的一个物理文件,命名形式为{table_name}.ibd。物理文件按page切分,这些page主要分为两类:存储表空间元信息的page和存储表空间用户数据的page。存储用户数据的page暂不关心,这里主要讨论表空间元信息page。
##########################################################
创建InnoDB表
5.6版本,在创建InnoDB表过程中,若发生crash,会导致服务无法启动。
背景
每个InnoDB表A创建成功后有两个文件A.frm和A.ibd。建表流程如下:
-
创建A.frm
-
创建A.ibd
-
初始化A.ibd
-
将表A加入InnoDB字典
若crash发生在步骤2之后,则只保留一个完整的A.frm和一个空文件A.idb。
崩溃恢复
在上述的crash发生后,下一次启动则需要做崩溃恢复。崩溃恢复的一个逻辑是需要遍历数据目录下的所有.ibd文件,验证文件与字典的一致性。
对于长度为0的.ibd 文件,报错并跳过,继续检测下一个表。
以上是5.5和5.6共有的逻辑。但5.6的一个新特性破坏了这个规则。
远程目录
5.6支持create table的时候指定其他目录。语法是create table 里新增参数DATA DIRECTORY.这样一个表就可能存在多个表空间。每个表空间对应一个数据结构(fsp_open_info).
这意味着在崩溃恢复过程中,需要验证哪一个表空间是可用的(fil_validate_single_table_tablespace),
验证的方法是尝试读取该表空间的第一个page,若可用则将对应的fsp_open_info::success设置为TRUE。
而在读取本地默认表空间的第一个页时,若碰到读取失败,直接exit(1),导致程序直接退出。“若文件小于4个page就报错”的逻辑,是在这个exit之后。
分析改进
其实在这个场景下,多出来的A.frm和A.ibd并不会导致系统严重问题。由于表A还没有记录入系统字典,实际上只需要将这两个文件直接删掉即可。
因此5.6的这个新增要求过于苛刻。改进方法是将文件大小的判断提前,若发现小于4个page,则直接报错跳过这个表。
##############################
innodb_flush_log_at_trx_commit
简单说来,可选值的安全性从0->2->1递增,分别对应于mysqld 进程crash可能丢失 -> OS crash可能丢失 -> 事务安全。
直到2010年的某一天,Percona的CTO Vadim同学觉得这种一刀切的风格不够灵活,最好把这个变量设置成session级别,每个session自己控制。
但同时为了保持Super权限对提交行为的控制,同时增加了innodb_use_global_flush_log_at_trx_commit参数。 这两个参数的配合逻辑为:
1、若innodb_use_global_flush_log_at_trx_commit为OFF,则使用session.innodb_flush_log_at_trx_commit;
2、若innodb_use_global_flush_log_at_trx_commit为ON,则使用global .innodb_flush_log_at_trx_commit(此时session中仍能设置,但无效)
3、每个session新建时,以当前的global.innodb_flush_log_at_trx_commit 为默认值。
#############################