本文小编为大家详细介绍“mysql的frm文件报错怎么修复”,内容详细,步骤清晰,细节处理妥当,希望这篇“mysql的frm文件报错怎么修复”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

在mysql中,frm的意思为“表定义”,是描述数据表结构的文件。frm文件是用来保存每个数据表的元数据信息,包括表结构的定义等。frm文件跟数据库存储引擎无关,也就是任何存储引擎的数据表都必须有frm文件,命名方式为“数据表名.frm”。

本教程操作环境:windows7系统、mysql8版本、Dell G3电脑。

在mysql中,frm的意思为“表定义”,是描述数据表结构的文件。

在MYSQL中建立任何一张数据表,在其数据目录对应的数据库目录下都有对应表的.frm文件,.frm文件是用来保存每个数据表的元数据(meta)信息,包括表结构的定义等。

.frm文件跟数据库存储引擎无关,也就是任何存储引擎的数据表都必须有.frm文件,命名方式为数据表名.frm,如user.frm. .frm文件可以用来在数据库崩溃时恢复表结构。

通常frm文件是不会损坏的,但是如果出现特殊情况出现frm文件损坏也不要放弃希望,例如下面报错:

15082116:31:27[ERROR]/usr/local/mysql51/libexec/mysqld:Incorrectinformationinfile:'./t/test1.frm'

当修复MyISAM和InnoDB表时,MySQL服务会首先去调用frm文件,所以我们只能通过修复frm文件进行后面的数据恢复。

MySQL通过sql/table.cc的create_frm()函数创建frm文件,创建出来的frm文件是二进制文件,需要通过hexdump解析成16进制来分析。

create_frm()函数对frm文件头部定义的代码

/*Createa.frmfile*/Filecreate_frm(THD*thd,constchar*name,constchar*db,constchar*table,uintreclength,uchar*fileinfo,HA_CREATE_INFO*create_info,uintkeys,KEY*key_info){registerFilefile;ulonglength;ucharfill[IO_SIZE];intcreate_flags=O_RDWR|O_TRUNC;ulongkey_comment_total_bytes=0;uinti;if(create_info->options&HA_LEX_CREATE_TMP_TABLE)create_flags|=O_EXCL|O_NOFOLLOW;/*Fixthiswhenwehavenew.frmfiles;Currentlimitis4Grows(QQ)*/if(create_info->max_rows>UINT_MAX32)create_info->max_rows=UINT_MAX32;if(create_info->min_rows>UINT_MAX32)create_info->min_rows=UINT_MAX32;if((file=mysql_file_create(key_file_frm,name,CREATE_MODE,create_flags,MYF(0)))>=0){uintkey_length,tmp_key_length,tmp,csid;bzero((char*)fileinfo,64);/*header*/fileinfo[0]=(uchar)254;fileinfo[1]=1;fileinfo[2]=FRM_VER+3+test(create_info->varchar);fileinfo[3]=(uchar)ha_legacy_type(ha_checktype(thd,ha_legacy_type(create_info->db_type),0,0));fileinfo[4]=1;int2store(fileinfo+6,IO_SIZE);/*Nextblockstartshere*//*Keepinsyncwithpack_keys()inunireg.ccForeachkey:8bytesforthekeyheader9bytesforeachkey-part(MAX_REF_PARTS)NAME_LENbytesforthename1bytefortheNAMES_SEP_CHAR(beforethename)Forallkeys:6bytesfortheheader1bytefortheNAMES_SEP_CHAR(afterthelastname)9extrabytes(paddingforsafety?alignment?)*/for(i=0;i<keys;i++){DBUG_ASSERT(test(key_info[i].flags&HA_USES_COMMENT)==(key_info[i].comment.length>0));if(key_info[i].flags&HA_USES_COMMENT)key_comment_total_bytes+=2+key_info[i].comment.length;}key_length=keys*(8+MAX_REF_PARTS*9+NAME_LEN+1)+16+key_comment_total_bytes;length=next_io_size((ulong)(IO_SIZE+key_length+reclength+create_info->extra_size));int4store(fileinfo+10,length);tmp_key_length=(key_length<0xffff)?key_length:0xffff;int2store(fileinfo+14,tmp_key_length);int2store(fileinfo+16,reclength);int4store(fileinfo+18,create_info->max_rows);int4store(fileinfo+22,create_info->min_rows);/*fileinfo[26]issetinmysql_create_frm()*/fileinfo[27]=2;//Uselongpack-fields/*fileinfo[28&29]issettokey_info_lengthinmysql_create_frm()*/create_info->table_options|=HA_OPTION_LONG_BLOB_PTR;//Useportableblobpointersint2store(fileinfo+30,create_info->table_options);fileinfo[32]=0;//Nofilenameanymorefileinfo[33]=5;//Markfor5.0frmfileint4store(fileinfo+34,create_info->avg_row_length);csid=(create_info->default_table_charset?create_info->default_table_charset->number:0);fileinfo[38]=(uchar)csid;/*Infutureversions,wewillstoreinfileinfo[39]thevaluesoftheTRANSACTIONALandPAGE_CHECKSUMclausesofCREATETABLE.*/fileinfo[39]=0;fileinfo[40]=(uchar)create_info->row_type;/*NextfewbyteswhereforRAIDsupport*/fileinfo[41]=(uchar)(csid>>8);fileinfo[42]=0;fileinfo[43]=0;fileinfo[44]=0;fileinfo[45]=0;fileinfo[46]=0;int4store(fileinfo+47,key_length);tmp=MYSQL_VERSION_ID;//Storetoavoidwarningfromint4storeint4store(fileinfo+51,tmp);int4store(fileinfo+55,create_info->extra_size);/*59-60isreservedforextra_rec_buf_length,61fordefault_part_db_type*/int2store(fileinfo+62,create_info->key_block_size);bzero(fill,IO_SIZE);for(;length>IO_SIZE;length-=IO_SIZE){if(mysql_file_write(file,fill,IO_SIZE,MYF(MY_WME|MY_NABP))){(void)mysql_file_close(file,MYF(0));(void)mysql_file_delete(key_file_frm,name,MYF(0));return(-1);}}}else{if(my_errno==ENOENT)my_error(ER_BAD_DB_ERROR,MYF(0),db);elsemy_error(ER_CANT_CREATE_TABLE,MYF(0),table,my_errno);}return(file);}/*create_frm*/

open_binary_frm()函数对对frm索引部分定义的代码

for(i=0;i<keys;i++,keyinfo++){keyinfo->table=0;//Updatedinopen_frmif(new_frm_ver>=3){keyinfo->flags=(uint)uint2korr(strpos)^HA_NOSAME;keyinfo->key_length=(uint)uint2korr(strpos+2);keyinfo->key_parts=(uint)strpos[4];keyinfo->algorithm=(enumha_key_alg)strpos[5];keyinfo->block_size=uint2korr(strpos+6);strpos+=8;}else{keyinfo->flags=((uint)strpos[0])^HA_NOSAME;keyinfo->key_length=(uint)uint2korr(strpos+1);keyinfo->key_parts=(uint)strpos[3];keyinfo->algorithm=HA_KEY_ALG_UNDEF;strpos+=4;}keyinfo->key_part=key_part;keyinfo->rec_per_key=rec_per_key;for(j=keyinfo->key_parts;j--;key_part++){*rec_per_key++=0;key_part->fieldnr=(uint16)(uint2korr(strpos)&FIELD_NR_MASK);key_part->offset=(uint)uint2korr(strpos+2)-1;key_part->key_type=(uint)uint2korr(strpos+5);//key_part->field=(Field*)0;//Willbefixedlaterif(new_frm_ver>=1){key_part->key_part_flag=*(strpos+4);key_part->length=(uint)uint2korr(strpos+7);strpos+=9;}else{key_part->length=*(strpos+4);key_part->key_part_flag=0;if(key_part->length>128){key_part->length&=127;/*purecov:inspected*/key_part->key_part_flag=HA_REVERSE_SORT;/*purecov:inspected*/}strpos+=7;}key_part->store_length=key_part->length;}}keynames=(char*)key_part;strpos+=(strmov(keynames,(char*)strpos)-keynames)+1;//readingindexcommentsfor(keyinfo=share->key_info,i=0;i<keys;i++,keyinfo++){if(keyinfo->flags&HA_USES_COMMENT){keyinfo->comment.length=uint2korr(strpos);keyinfo->comment.str=strmake_root(&share->mem_root,(char*)strpos+2,keyinfo->comment.length);strpos+=2+keyinfo->comment.length;}DBUG_ASSERT(test(keyinfo->flags&HA_USES_COMMENT)==(keyinfo->comment.length>0));}

hexdump是Linux下的一个二进制文件查看工具,可以将二进制文件转换为ASCII、10进制、16进制或8进制进行查看。

hexdump参数-C每一字节以16进制显示,一行共16个字节,显示十六进制存储的文本内容-b每一字节以八进制显示,一行共16个字节,一行开始以十六进制显示偏移值;0000000177105114106002001001000000000000000000000000000-c每一字节以ASCII字符显示,其余同上;0000000177ELF002001001\0\0\0\0\0\0\0\0\0-n只解释指定长度字节单位:默认十进制,0x或0X开头则为16进制,0开头则为8进制。默认为字节,b则为512字节,k则为1024字节,m则为1048576字节-d双字节十进制显示-o双字节八进制显示-v去除中间显示的“*”字符-x双字节十六进制显示-e格式化参数

实例版本与表字符集:

参考:https://www.percona.com/blog/2015/07/09/obtain-mysql-version-frm-file/

建表的实例版本0x033语句hexdump-s0x33-n2-v-dtable.frm[root@test1~]#hexdump-s0x33-n2-v-d/data/3308/test/test1.frm0000033501530000035所以版本为5.1.53,因为5.1/5.5和5.6在字段类型定义上有不同,所以确定好建表实例版本很重要,字段类型定义见下面表字符集0x02621=utf808=latin11c=GBK语句hexdump-s0x26-n1table.frm

frm列属性:

、列序号(初始列序号为4)、字段长度,整形长度、字段长度,latin1字符集字符类型长度,GBK字符集字符类型varchar长度*2,varchar(30)相当于就是60字节长度,换成16进制是3c,utf8字符集字符类型varchar长度*3,varchar(30)相当于就是90字节长度,换成16进制是5a、、、、、Flagsforzerofill,unsigned,etc.(int1b)、Additionalflags,andscaleifdecimal/numeric(DEFAULTNULL80,NOTNULL40,DEFAULT'VALUE'00)、代码定义unireg_type,AUTO_INCREMENTof、、代码定义interval_nr、字段类型、字符集、备注长度、备注长度

字段类型(注意5.6版本字段类型有不同,会影响数据恢复):

Datatypeforv5.1&v5.5(v5.6)fe=charfa=mediumtextf6=decimalfc=textof=varchar01=tinyint02=smallint03=int04=float05=real07=timestamp(v5.611=timestamp)08=bigint09=mediumint10=bitob=time(v5.613=time)oc=datetime(v5.612=datetime)0d=year0e=date

表中所含索引:

偏移量在0x1000之后的一段是frm索引部分,用hexdump-C打开后很容易找到0x1000:有几个索引0x1001:全部索引包含几个字段索引名是明文,具体索引结构见示例。

表:

CREATETABLE`test3`(`a`int(11)NOTNULL,`b`varchar(10)DEFAULTNULL,`c`int(11)NOTNULL,PRIMARYKEY(`a`),UNIQUEKEY`uniq_1`(`b`,`c`),KEY`idx_1`(`c`,`b`),KEY`idx_2`(`c`))ENGINE=InnoDBDEFAULTCHARSET=utf8

十六进制文件打开:

[root@test1~]#hexdump-C/data/3308/test/test3.frm00000000fe010a0c030000100100003000007405|...........0..t.|0000001028000000000000000000000279000900|(...........y...|0000002000050000000021000000000000000074|......!........t|#表字符集00000030050000e9c30000100000000000000000|................|#标红的是建表实例版本号000000402f2f0000200000000000000000000000|//.............|0000005000000000000000000000000000000000|................|*00001000040600001d0000000400010000000180|................|000010100200001b400400680022000200000002|....@..h."......|000010208006000000801e0003802500001b4004|..........%...@.|0000103000690022000200000003802500001b40|.i.".......%...@|000010400400028006000000801e000100040001|................|0000105000000003802500001b400400ff505249|.....%...@...PRI|000010604d415259ff756e69715f31ff6964785f|MARY.uniq_1.idx_|0000107031ff6964785f32ff0000000000000000|1.idx_2.........|0000108000000000000000000000000000000000|................|*0000157000000000ff0000000000000000000000|................|0000158000000000000000000000000000000000|................|0000159000000000000000000000000000000600|................|000015a0496e6e6f444200000000000000000000|InnoDB..........|000015b000000000000000000000000000000000|................|*000020009a010010000000000000000000000000|................|0000201000000000000000000000000000000000|................|*00002100010003003f0034000000280008000000|....?.4...(.....|0000211000000000000050001600010000000000|......P.........|000021203f000403021429202020202020202020|?.....)|0000213020202020202020202020202020202020||0000214020202020202020202020202020202000|.|0000215004000261000500026200060002630004|...a....b....c..|00002160020b0b000200001b40000000033f0000|........@....?..|0000217005021e1e0006000000800000000f2100|..............!.|000021800006020b0b002500001b40000000033f|......%...@....?|000021900000ff61ff62ff63ff00|...a.b.c..|

通过上面的颜色区分,圈出的黄色部分是索引属性,下面红蓝绿三色是三列属性。

列属性结构:

红色部分:字段序号(4开始,4、5、6就是字段第一第二第三)

蓝色部分:字段长度

棕色部分:是否为空

绿色部分:字段类型

黄色部分:字符集

索引属性结构:

索引头部:

淡蓝色部分:索引统计数

粉色部分:索引总共有多少列

索引主体:

棕色部分:是否唯一索引

红色部分:表中列的序号

绿色部分:表中对应列的属性

字段默认值:

字段默认值不保存在字段属性中,而是保存在描述表引擎的那段中int类型默认值保存为十六进制需转换十进制,char类型默认值保存为十六进制文本可通过hexdump-C直接看到如果没有索引段则默认值在,0x1011后,如果有索引段,则位置顺延例如表CREATETABLE`test1`(`a`int(11)NOTNULLDEFAULT'2010',`b`varchar(10)NOTNULLDEFAULT'2011',`c`int(11)default'30',`d`varchar(10)NOTNULLDEFAULT'Yes')engine=innodbdefaultcharset=utf8;*00001000000000000200ff000000000000000000|................|00001010feda0700000432303131000000000000|......2011......|0000102000000000000000000000000000000000|................|00001030000000001e0000000359657300000000|.........Yes....|0000104000000000000000000000000000000000|................|000010500000000000000000000600496e6e6f44|...........InnoD|0000106042000000000000000000000000000000|B...............|0000107000000000000000000000000000000000|................|*columna:da070000columnb:04323031310000000000000000000000000000000000000000000000000000columnc:1e000000columnd:03596573000000000000000000000000000000000000000000000000000000需要注意char字段的默认值是根据字段长度和字符集相关的,如上表varchar(10),utf8是3bit,就是30个十六进制长度。

读到这里,这篇“mysql的frm文件报错怎么修复”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。