MYSQL ERROR 1146 Table doesnt exist 解析

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: 原创转载请注明出处 源码版本 5.7.14 在MYSQL使用innodb的时候我们有时候会看到如下报错: ERROR 1146 (42S02): Table 'test.test1bak' doesn't exist 首先总结下原因: 缺少frm文件 innodb数据字典不包含这个表 我们重点讨论情况2,因为情况1是显而易见的。

原创转载请注明出处

源码版本 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 Files
 502  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数据字典自然不包含这些表了。其实也是上面描述的原理 。
?那么正确的拷贝的方式一定是停机后,整个数据目录进行拷贝,而不是仅仅拷贝需要的库的目录,否则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 */
****/*--------------------------------------*/**** 

作者微信:

微信.jpg

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1天前
|
存储 关系型数据库 MySQL
MySQL Change Buffer 深入解析:概念、原理及使用
MySQL Change Buffer 深入解析:概念、原理及使用
MySQL Change Buffer 深入解析:概念、原理及使用
|
1天前
|
存储 关系型数据库 MySQL
mysql optimizer_switch : 查询优化器优化策略深入解析
mysql optimizer_switch : 查询优化器优化策略深入解析
|
2天前
|
SQL 监控 关系型数据库
深入解析MySQL死锁:原因、检测与解决方案
深入解析MySQL死锁:原因、检测与解决方案
|
1天前
|
缓存 关系型数据库 MySQL
MySQL Buffer Pool 解析:原理、组成及作用
MySQL Buffer Pool 解析:原理、组成及作用
|
21小时前
|
SQL 关系型数据库 MySQL
ClickHouse(23)ClickHouse集成Mysql表引擎详细解析
ClickHouse的MySQL引擎允许执行`SELECT`查询从远程MySQL服务器。使用`MySQL(&#39;host:port&#39;, &#39;database&#39;, &#39;table&#39;, &#39;user&#39;, &#39;password&#39;[,...])`格式连接,支持简单`WHERE`子句在MySQL端处理,复杂条件和`LIMIT`在ClickHouse端执行。不支持`NULL`值,用默认值替换。系列文章涵盖ClickHouse安装、集群搭建、表引擎解析等主题。[链接](https://zhangfeidezhu.com/?p=468)有更多
5 0
|
1天前
|
SQL 关系型数据库 MySQL
MySQL外键约束行为解析:CASCADE, NO ACTION, RESTRICT, SET NULL
MySQL外键约束行为解析:CASCADE, NO ACTION, RESTRICT, SET NULL
7 0
|
1天前
|
SQL 存储 关系型数据库
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server
|
1天前
|
存储 关系型数据库 MySQL
深入探索MySQL:成本模型解析与查询性能优化
深入探索MySQL:成本模型解析与查询性能优化
|
1天前
|
存储 关系型数据库 MySQL
MySQL Doublewrite Buffer(双写缓冲区)深入解析:原理及作用
MySQL Doublewrite Buffer(双写缓冲区)深入解析:原理及作用
|
2天前
|
SQL 关系型数据库 MySQL
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version

推荐镜像

更多