共計 8419 個字符,預計需要花費 22 分鐘才能閱讀完成。
今天就跟大家聊聊有關如何解析 MYSQL ERROR 1146 Table doesnt exist,可能很多人都不太了解,為了讓大家更加了解,丸趣 TV 小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
源碼版本 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 的數據字典,主要的包含:
INNODB_SYS_columns
INNODB_SYS_FIELDS
INNODB_SYS_TABLES
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
其實大概步驟就是
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 + 樹也是存在其中,用源碼解釋一下:
/**********************************************************************//**
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 */
****/*--------------------------------------*/****
看完上述內容,你們對如何解析 MYSQL ERROR 1146 Table doesnt exist 有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注丸趣 TV 行業資訊頻道,感謝大家的支持。