今天就跟大家聊聊有关如何解析MYSQL ERROR 1146 Table doesnt exist ,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

源码版本 5.7.14

在MYSQL使用innodb的时候我们有时候会看到如下报错:

ERROR1146(42S02):Table'test.test1bak'doesn'texist

首先总结下原因:

缺少frm文件

innodb数据字典不包含这个表

我们重点讨论情况2,因为情况1是显而易见的。
?在使用innodb存储引擎的时候某些时候我们show tables能够看到这个表,但是如果进行任何操作会报错如下:

mysql>showtables;|test1bak|mysql>desctest1bak;ERROR1146(42S02):Table'test.test1bak'doesn'texist

也许你会说我明明能够看到这个表啊,为什么访问还会报错呢?其实要清楚innodb有自己的数据字典,只要有frm 文件存在show tables就能看到,但是最终是否能够正常打开表结构在innodb中还依赖于innodb的数据字典,主要的包含:

INNODB_SYS_columns

INNODB_SYS_FIELDS

INNODB_SYS_TABLES

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,他实际上是一个位图表示方式,分别表示如下信息:

/*TableandtablespaceflagsaregenerallynotusedfortheAntelopefileformatexceptfortheloworderbit,whichisuseddifferentlydependingonwheretheflagsarestored.====================Loworderflagsbit=========================|REDUNDANT|COMPACT|COMPRESSEDandDYNAMICSYS_TABLES.TYPE|1|1|1dict_table_t::flags|0|1|1FSP_SPACE_FLAGS|0|0|1fil_space_t::flags|0|0|1/**WidthoftheCOMPACTflag*/#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/**WidthoftheSHAREDtablespaceflag.Itisusedtoidentifytablesthatexistinsideasharedgeneraltablespace.IfatableiscreatedwiththeTABLESPACE=tsnameoption,anolderenginewillnotbeabletofindthattable.ThisflagpreventsolderenginesfromattemptingtoopenthetableandallowsInnoDBtoquicklyfindthetablespace.*/#defineDICT_TF_WIDTH_SHARED_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';其type为97二进制为01100001:使用DATADIRECTORY建立使用ATOMIC_BLOBS且无压缩则DYNAMIC格式详见:15.5.5CreatingaFile-Per-TableTablespaceOutsidetheDataDirectory如果我们建立如下的表:CREATETABLESPACEtt1ADDDATAFILE'/root/mysql5.7.14/tt1.ibd';CREATETABLEtsh(c1INT)TABLESPACEtt1ROW_FORMAT=COMPACT;其type为129二进制为10000001:使用TABLESPACE语法建立不使用ATOMIC_BLOBS且无压缩则为COMPACT格式详见:15.5.9InnoDBGeneralTablespaces

我们可以看到使用8位一个字节而已就可以表示出大量的信息,这也是位图的优势,其他比如 MTYPE/PRTYPE也是这种表示方式

接下来我们回到主题,需要看看这个错到底是哪里报错来的?进行trace后如下,我们来看看主要部分:

注意这里的trace是mysql debug版本下查看函数调用的主要方法参考官方文档26.5.1.2 Creating Trace Files

502T@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_table_check_if_in_cache_low125508T@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_table_check_if_in_cache_low125513T@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:|||||||||||||||<dict_table_check_if_in_cache_low125518T@2:|||||||||||||||>btr_cur_search_to_nth_level519T@2:|||||||||||||||<btr_cur_search_to_nth_level2005520T@2:||||||||||||||<dict_load_table_one3084521T@2:|||||||||||||<dict_load_table2882522T@2:||||||||||||<dict_table_open_on_name1292523T@2:|||||||||||<ha_innobase::open_dict_table6676524T@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:|||||||||||||<print_buffer_to_file2332529T@2:||||||||||||<error_log_print2357530T@2:|||||||||||<sql_print_warning2384

其实大概步骤就是

Checks if a table is in the dictionary cache
根据dict_sys->table_hash寻找

Loads a table definition and also all its index definitions.
通过扫描字典的B+树进行加载

如果不能找到则报错

这样也就解释了为什么show tables能够看到但是select却报错Table doesn't exist ,而从原理上讲show tables只是查看了frm文件。


另外这里也提一个案列,曾经有一个朋友问我他将整个库目录都拷贝了,但是表能看到但是一操作就报Table doesn't exist,显然他没有拷贝ibdata1,数据字典的引导信息都存在这里面文件的第7个page中,其b+树也是存在其中,用源码解释一下:

/**********************************************************************//**Getsapointertothedictionaryheaderandx-latchesitspage.@returnpointertothedictionaryheader,pagex-latched*/dict_hdr_t*dict_hdr_get(/*=========*/mtr_t*mtr)/*!<in:mtr*/{buf_block_t*block;dict_hdr_t*header;block=buf_page_get(page_id_t(DICT_HDR_SPACE,DICT_HDR_PAGE_NO),univ_page_size,RW_X_LATCH,mtr);header=DICT_HDR+buf_block_get_frame(block);buf_block_dbg_add_level(block,SYNC_DICT_HEADER);return(header);}

注意这里的 DICT_HDR_SPACE, DICT_HDR_PAGE_NO分别是宏定义

/*Spaceidandpagenowherethedictionaryheaderresides*/#defineDICT_HDR_SPACE0/*theSYSTEMtablespace*/#defineDICT_HDR_PAGE_NOFSP_DICT_HDR_PAGE_NO#defineFSP_DICT_HDR_PAGE_NO7/*!<datadictionaryheaderpage,intablespace0*/

space 0就是ibdata1的space_no,7当然就是引导块,这哥们连ibdata1都没拷贝,当然innodb数据字典自然不包含这些表了。其实也是上面描述的原理 。
?那么正确的拷贝的方式一定是停机后,整个数据目录进行拷贝,而不是仅仅拷贝需要的库的目录,否则innodb数据字典是不能正常加载的。

最后附带space 0的部分块解释

/*--------------------------------------*/#defineFSP_XDES_OFFSET0/*!<extentdescriptor*/#defineFSP_IBUF_BITMAP_OFFSET1/*!<insertbufferbitmap*//*TheibufbitmappagesaretheoneswhosepagenumberisthenumberaboveplusamultipleofXDES_DESCRIBED_PER_PAGE*/#defineFSP_FIRST_INODE_PAGE_NO2/*!<ineverytablespace*//*Thefollowingpagesexistinthesystemtablespace(space0).*/#defineFSP_IBUF_HEADER_PAGE_NO3/*!<insertbufferheaderpage,intablespace0*/#defineFSP_IBUF_TREE_ROOT_PAGE_NO4/*!<insertbufferB-treerootpageintablespace0*//*Theibuftreerootpagenumberintablespace0;itsfseginodeisonthepagenumberFSP_FIRST_INODE_PAGE_NO*/#defineFSP_TRX_SYS_PAGE_NO5/*!<transactionsystemheader,intablespace0*/#defineFSP_FIRST_RSEG_PAGE_NO6/*!<firstrollbacksegmentpage,intablespace0*/#defineFSP_DICT_HDR_PAGE_NO7/*!<datadictionaryheaderpage,intablespace0*/****/*--------------------------------------*/****

看完上述内容,你们对如何解析MYSQL ERROR 1146 Table doesnt exist 有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。