当前位置: 首页 > 科技观察

关于MySQLERROR1146Tabledoesn'texist

时间:2023-03-20 18:05:52 科技观察

☉sourcecodeversion5.7.14在MYSQL中使用innodb时,有时会出现如下错误的分析:ERROR1146(42S02):Table'test.test1bak'doesn'texistfirstsummarize原因:missingfrmfileinnodbdatadictionarydoesnotcontainthistable我们关注案例2,因为案例1很明显。在使用innodb存储引擎的时候,有时我们在showtables中可以看到这张表,但是如果我们进行任何操作,就会报错如下:mysql>showtables;|test1bak|mysql>desctest1bak;ERROR1146(42S02):Table'test.test1bak'does'texist也许你会说我明明可以看到这张表,为什么访问它还是报错?其实大家一定清楚,innodb是有自己的数据字典的,只要有frm文件,showtables中就可以看到,但是到底能不能正常打开innodb中的表结构还得看innodb的数据字典,主要包括:1.INNODB_SYS_columns2,INNODB_SYS_FIELDS3,INNODB_SYS_TABLES4,INNODB_SYS_INDEXES如果出现错误,我们需要先查看INNODB_SYS_TABLES是否包含这个表的信息。可能这些数据字典中有些列不是那么清楚,比如mysql>select*frominformation_schema.innodb_sys_tableswherename='test/kkkkm1';+----------+---------------+-------+--------+-------+------------+-------------+----------------+------------+|TABLE_ID|NAME|FLAG|N_COLS|SPACE|FILE_FORMAT|ROW_FORMAT|ZIP_PAGE_SIZE|SPACE_TYPE|+----------+------------+------+--------+-------+------------+------------+----------------+-------------+|374|test/kkkkm1|33|6|540|Barracuda|Dynamic|0|Single|+--------+-------------+--------+--------+--------+------------+-----------+----------------+------------+比如这里的FLAG列为33,他其实以上是一个位图表示,分别代表以下信息:/*表和表空间标志一般不用于Antelope文件格式,除了loworder位,根据恢复标志的位置不同而不同。=====================Loworderflagsbit==========================|冗余|COMPACT|COMPRESSEDandDYNAMICSYS_TABLES.TYPE|1|1|1dict_table_t::flags|0|1|1FSP_SPACE_FLAGS|0|0|1fil_space_t::flags|0|0|1/**紧凑标志的宽度*/#defineDICT_TF_WIDTH_COMPACT1/**WidthoftheZIP_SSIZEflag*/#defineDICT_TF_WIDTH_ZIP_SSIZE4/**WidthoftheATOMIC_BLOBSflag.TheAntelopefileformatsbrokeupBLOBandTEXTfields,storingthefirst768bytesintheclusteredindex.Barracudarowformatsstorethewholeblobortextfieldoff-pageatomically.Secondaryindexesarecreatedfromthisexternaldatausingrow_ext_ttocachetheBLOBprefixes.*/#defineDICT_TF_WIDTH_ATOMIC_BLOBS1/**IfatableiscreatedwiththeMYSQLoptionDATADIRECTORYandinnodb-file-per-table,anolderenginewillnotbeabletofindthattable.ThisflagpreventsolderenginesfromattemptingtoopenthetableandallowsInnoDBtoupdate_create_info()accordingly.*/#defineDICT_TF_WIDTH_DATA_DIR1/**共享表空间标志的宽度。它用于识别存在于共享通用表空间中的表。如果表是使用TABLESPACE=tsname选项创建的,则较旧的引擎将无法找到该表。此标志可防止焊接引擎尝试打开表并允许InnoDB快速找到表空间。_/#defineDICTHARED_SPACE1接下来分析一下FLAG为什么是33如下:33的二进制值为00100001,从低位1开始:从源码注释来看,标准的COMPACT/COMPRESSED/DYNAMIC都是10000:ZIP_SSIZEflag这四位是用于支持COMPRESSED1等压缩功能:ATOMIC_BLOBSflag这是COMPACT和DYNAMIC的主要区别,请看源码注释0:DATADIRECTORYandinnodb-file-per-tableflag支持DATADIRECTORY语法0:SHAREDtablespaceflag支持TABLESPACE语法然后我们测试它:如果我们创建下表:CREATETABLEt2(c1INTPRIMARYKEY)TABLESPACE=innodb_file_per_tableDATADIRECTORY='/root/mysql5.7.14/percona-server-5.7.14-7/mysql-test/var/mysqld.1';其类型为97,其二进制值为01100001:使用DATADIRECTORY创建ATOMIC_BLOBS且不压缩,则DYNAMIC格式详见:15.5.5CreatingaFile-Per-TableTablespaceOutsidetheDataDirectory如果我们创建下表:创建表空间tt1添加数据文件'/root/mysql5.7.14/tt1.ibd';创建表tsh(c1INT)TABLESPACEtt1ROW_FORMAT=COMPACT;其类型为129,二进制为10000001:使用TABLESPACE语法创建,不使用ATOMIC_BLOBS且不压缩,则为COMPACT格式见:15.5.9InnoDBGeneralTablespaces。我们可以看到,大量的信息仅用8位和一个字节就可以表示。这也是位图的优势。其他的比如MTYPE/PRTYPE也是这样表示的。接下来,回归正题,需要看这个错误从何而来?执行完trace,我们来看一下main部分:注意这里的trace是mysqldebug版本查看函数调用的主要方法。参考官方文档26.5.1.2CreatingTraceFiles502T@2:|||||||||||>ha_innobase::open_dict_table503T@2:|||||||||||>dict_table_open_on_name504T@2:||||||||||||dict_table_open_on_name:table:'test/test1bak'505T@2:|||||||||||>dict_table_check_if_in_cache_low506T@2:||||||||||||dict_table_check_if_in_cache_low:table:'test/test1bak'507T@2:|||||||||||||dict_load_table509T@2:||||||||||||||dict_load_table:loadingtable:'test/test1bak'510T@2:|||||||||||||>dict_table_check_if_in_cache_low511T@2:|||||||||||||||dict_table_check_if_in_cache_low:table:'test/test1bak'512T@2:||||||||||||||dict_load_table_one514T@2:|||||||||||||dict_load_table_one:table:test/test1bak515T@2:||||||||||||||>dict_table_check_if_in_cache_low516T@2:||||||||||||||||dict_table_check_if_in_cache_low:table:'SYS_TABLES'517T@2:||||||||||||||btr_cur_search_to_nth_level519T@2:|||||||||||||||sql_print_warning525T@2:|||||||||||>error_log_print526T@2:||||||||||||>print_buffer_to_file527T@2:||||||||||||||enter:buffer:InnoDB:Cannotopentabletest/test1bakfromtheinternaldatadictionaryofInnoDBthoughthe.frmfileforthetableexists.Pleaserefertohttp://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting.htmlforhowtoresolvetheissue.528T@2:|||||||||||||table_hash进行搜索2.加载表定义及其所有索引定义。通过扫描字典3的B+树来加载,如果找不到就会报错。这也解释了为什么showtables可以看到但是select报错Tabledoesn'texist,原则上showtables只是查看frm文件另外,这里还有一个案例。曾经有朋友问我,他复制了整个库目录,但是能看到表,但是一操作就报Tabledoesn'texist。很明显他没有复制ibdata1,数据字典的引导信息它们都存在这里文件的第七页,b+树也存在里面,用源码解释一下:/********************************************************************************Getsapointertothedictionaryheaderandx-latchesitspage.@returnpointertothedictionaryheader,pagex-latched*/dict_hdr_t*dict_hdr_get(/*==========*/mtr_t*mtr)/*!