如何进行MySQL ERROR 1146 Table doesnt exist的解析

45次阅读
没有评论

共计 8526 个字符,预计需要花费 22 分钟才能阅读完成。

行业资讯    
数据库    
如何进行 MySQL ERROR 1146 Table doesnt exist 的解析

本篇文章为大家展示了如何进行 MySQL ERROR 1146 Table doesnt exist 的解析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

☉源码版本 5.7.14

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

ERROR 1146 (42S02): Table  test.test1bak  doesn t exist

首先总结下原因:

缺少 frm 文件

innodb 数据字典不包含这个表

我们重点讨论情况 2,因为情况 1 是显而易见的。

在使用 innodb 存储引擎的时候某些时候我们 show tables 能够看到这个表, 但是如果进行任何操作会报错如下:

mysql  show tables; | test1bak | mysql  desc test1bak ; ERROR 1146 (42S02): Table  test.test1bak  doesn t exist

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

1、INNODB_SYS_columns

2、INNODB_SYS_FIELDS

3、INNODB_SYS_TABLES

4、INNODB_SYS_INDEXES

如果报错出现我们需要首先查看的是 INNODB_SYS_TABLES 是否包含了这个表的信息。也许在这些数据字典中也许某些列并显示并不是那么明确,比如

mysql  select * from information_schema.innodb_sys_tables where name= 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,他实际上是一个位图表示方式,分别表示如下信息:

/* Table and tablespace flags are generally not used for the Antelope file format except for the low order bit, which is used differently depending on where the flags are stored. ==================== Low order flags bit ========================= | REDUNDANT | COMPACT | COMPRESSED and DYNAMIC SYS_TABLES.TYPE | 1 | 1 | 1 dict_table_t::flags | 0 | 1 | 1 FSP_SPACE_FLAGS | 0 | 0 | 1 fil_space_t::flags | 0 | 0 | 1 /** Width of the COMPACT flag */ #define DICT_TF_WIDTH_COMPACT 1 /** Width of the ZIP_SSIZE flag */ #define DICT_TF_WIDTH_ZIP_SSIZE 4 /** Width of the ATOMIC_BLOBS flag. The Antelope file formats broke up BLOB and TEXT fields, storing the first 768 bytes in the clustered index. Barracuda row formats store the whole blob or text field off-page atomically. Secondary indexes are created from this external data using row_ext_t to cache the BLOB prefixes. */ #define DICT_TF_WIDTH_ATOMIC_BLOBS 1 /** If a table is created with the MYSQL option DATA DIRECTORY and innodb-file-per-table, an older engine will not be able to find that table. This flag prevents older engines from attempting to open the table and allows InnoDB to update_create_info() accordingly. */ #define DICT_TF_WIDTH_DATA_DIR 1 /** Width of the SHARED tablespace flag. It is used to identify tables that exist inside a shared general tablespace. If a table is created with the TABLESPACE=tsname option, an older engine will not be able to find that table. This flag prevents older engines from attempting to open the table and allows InnoDB to quickly find the tablespace. */ #define DICT_TF_WIDTH_SHARED_SPACE 1

接下来我们分析一下为什么是 FLAG 是 33 如下:

33 的二进制为 00100001 从低位开始
1: 从源码注释来看本位 COMPACT/COMPRESSED/DYNAMIC 均为 1
0000: ZIP_SSIZE flag  这四位用于支持压缩功能如 COMPRESSED
1:ATOMIC_BLOBS flag  这一位是 COMPACT 和 DYNAMIC 主要区别所在, 请看源码注释
0:DATA DIRECTORY and innodb-file-per-table flag 为了支持 DATA DIRECTORY 语法
0:SHARED tablespace flag 为了支持 TABLESPACE 语法 

然后我们测试一下:

 如果我们建立如下的表: 
CREATE TABLE t2 (c1 INT PRIMARY KEY) TABLESPACE = innodb_file_per_table 
DATA DIRECTORY =  /root/mysql5.7.14/percona-server-5.7.14-7/mysql-test/var/mysqld.1  
其 type 为 97 二进制为  01100001: 使用 DATA DIRECTORY 建立使用 ATOMIC_BLOBS 且无压缩则 DYNAMIC 格式  
详见:15.5.5 Creating a File-Per-Table Tablespace Outside the Data Directory 
如果我们建立如下的表: 
CREATE TABLESPACE tt1 ADD DATAFILE  /root/mysql5.7.14/tt1.ibd  
CREATE TABLE tsh (c1 INT ) TABLESPACE tt1 ROW_FORMAT=COMPACT ; 
其 type 为 129 二进制为  10000001: 使用 TABLESPACE 语法建立不使用 ATOMIC_BLOBS 且无压缩则为 COMPACT 格式  
详见:15.5.9 InnoDB General Tablespaces

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

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

注意这里的 trace 是 mysql debug 版本下查看函数调用的主要方法参考官方文档 26.5.1.2 Creating Trace Files502  T@2: | | | | | | | | | | | ha_innobase::open_dict_table

503 T@2: | | | | | | | | | | | |  dict_table_open_on_name 504 T@2: | | | | | | | | | | | | | dict_table_open_on_name: table:  test/test1bak  505 T@2: | | | | | | | | | | | | |  dict_table_check_if_in_cache_low 506 T@2: | | | | | | | | | | | | | | dict_table_check_if_in_cache_low: table:  test/test1bak  507 T@2: | | | | | | | | | | | | |  dict_table_check_if_in_cache_low 125 508 T@2: | | | | | | | | | | | | |  dict_load_table 509 T@2: | | | | | | | | | | | | | | dict_load_table: loading table:  test/test1bak  510 T@2: | | | | | | | | | | | | | |  dict_table_check_if_in_cache_low 511 T@2: | | | | | | | | | | | | | | | dict_table_check_if_in_cache_low: table:  test/test1bak  512 T@2: | | | | | | | | | | | | | |  dict_table_check_if_in_cache_low 125 513 T@2: | | | | | | | | | | | | | |  dict_load_table_one 514 T@2: | | | | | | | | | | | | | | | dict_load_table_one: table: test/test1bak 515 T@2: | | | | | | | | | | | | | | |  dict_table_check_if_in_cache_low 516 T@2: | | | | | | | | | | | | | | | | dict_table_check_if_in_cache_low: table:  SYS_TABLES  517 T@2: | | | | | | | | | | | | | | |  dict_table_check_if_in_cache_low 125 518 T@2: | | | | | | | | | | | | | | |  btr_cur_search_to_nth_level 519 T@2: | | | | | | | | | | | | | | |  btr_cur_search_to_nth_level 2005 520 T@2: | | | | | | | | | | | | | |  dict_load_table_one 3084 521 T@2: | | | | | | | | | | | | |  dict_load_table 2882 522 T@2: | | | | | | | | | | | |  dict_table_open_on_name 1292 523 T@2: | | | | | | | | | | |  ha_innobase::open_dict_table 6676 524 T@2: | | | | | | | | | | |  sql_print_warning 525 T@2: | | | | | | | | | | | |  error_log_print 526 T@2: | | | | | | | | | | | | |  print_buffer_to_file 527 T@2: | | | | | | | | | | | | | | enter: buffer: InnoDB: Cannot open table test/test1bak from the internal data dictionary of InnoDB though the .frm file for the table exists. Please refer to http://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting.html for how to resolve the issue. 528 T@2: | | | | | | | | | | | | |  print_buffer_to_file 2332 529 T@2: | | | | | | | | | | | |  error_log_print 2357 530 T@2: | | | | | | | | | | |  sql_print_warning 2384

☉其实大概步骤就是

1、Checks if a table is in the dictionary cache

根据 dict_sys- table_hash 寻找

2、Loads a table definition and also all its index definitions.

通过扫描字典的 B + 树进行加载

3、如果不能找到则报错

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

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

/**********************************************************************//** Gets a pointer to the dictionary header and x-latches its page. @return pointer to the dictionary header, page x-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 分别是宏定义

/* Space id and page no where the dictionary header resides */ #define DICT_HDR_SPACE 0 /* the SYSTEM tablespace */ #define DICT_HDR_PAGE_NO FSP_DICT_HDR_PAGE_NO #define FSP_DICT_HDR_PAGE_NO 7 /*!  data dictionary header page, in tablespace 0 */

space  0 就是 ibdata1 的 space_no,7 当然就是引导块,这哥们连 ibdata1 都没拷贝,当然 innodb 数据字典自然不包含这些表了。其实也是上面描述的原理  。

emsp; 那么正确的拷贝的方式一定是停机后,整个数据目录进行拷贝,而不是仅仅拷贝需要的库的目录,否则 innodb 数据字典是不能正常加载的。

附带 space 0 的部分块解释

/*--------------------------------------*/ #define FSP_XDES_OFFSET 0 /* !  extent descriptor */ #define FSP_IBUF_BITMAP_OFFSET 1 /* !  insert buffer bitmap */ /* The ibuf bitmap pages are the ones whose page number is the number above plus a multiple of XDES_DESCRIBED_PER_PAGE */ #define FSP_FIRST_INODE_PAGE_NO 2 /*!  in every tablespace */ /* The following pages exist in the system tablespace (space 0). */ #define FSP_IBUF_HEADER_PAGE_NO 3 /*!  insert buffer header page, in tablespace 0 */ #define FSP_IBUF_TREE_ROOT_PAGE_NO 4 /*!  insert buffer B-tree root page in tablespace 0 */ /* The ibuf tree root page number in tablespace 0; its fseg inode is on the page number FSP_FIRST_INODE_PAGE_NO */ #define FSP_TRX_SYS_PAGE_NO 5 /*!  transaction system header, in tablespace 0 */ #define FSP_FIRST_RSEG_PAGE_NO 6 /*!  first rollback segment page, in tablespace 0 */ #define FSP_DICT_HDR_PAGE_NO 7 /*!  data dictionary header page, in tablespace 0 */ ****/*--------------------------------------*/****

上述内容就是如何进行 MySQL ERROR 1146 Table doesnt exist 的解析,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注丸趣 TV 行业资讯频道。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-19发表,共计8526字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)