如何在删除ibdata1和ib_logfile的情况下恢复MySQL数据库
昨天,有个朋友对公司内部使用的一个MySQL实例开启binlog,但是在启动的过程中失败了(他也没提,为何会失败),在启动失败后,他删除了ibdata1和ib_logfile,后来,能正常启动了,但所有的表通过show tables能看到,但是select的过程中却报“Table doesn't exist”。
于是,建议他试试可传输表空间。
同时,自己也测试了下,确实可行。
测试版本 MySQL 5.6.32 社区版
恢复的基本步骤
1. 将原来的数据文件COPY到其它目录下。
2. 创建同名表,表结构必须保持一致。
3. 导出表空间
mysql> ALTER TABLE t DISCARD TABLESPACE;
4. 将原来的数据文件COPY回来
5. 导入表空间
mysql> ALTER TABLE t IMPORT TABLESPACE
下面的演示会略为复杂,主要是还原整个场景,并针对上述步骤中的2,4做了一个测试。
首先,创建测试数据
在这里创建两张表。之所以创建两张相同的表是为了方便后续的测试。
mysql> create table t1(id int,hiredate datetime);
Query OK, 0 rows affected (0.14 sec) mysql> create table t2(id int,hiredate datetime);
Query OK, 0 rows affected (0.01 sec) mysql> insert into t1 values(1,now());
Query OK, 1 row affected (0.06 sec) mysql> insert into t1 values(2,now());
Query OK, 1 row affected (0.00 sec) mysql> insert into t2 values(1,now());
Query OK, 1 row affected (0.00 sec) mysql> insert into t2 values(2,now());
Query OK, 1 row affected (0.00 sec)
关闭数据库
# /usr/test/mysql-5.6.32-linux-glibc2.5-x86_64/bin/mysqladmin shutdown -uroot -p123456 -h127.0.0.1 -P3310
删除ibdata1,ib_logfile0和ib_logfile1
[root@localhost data]# cd /data/
[root@localhost data]# ls
auto.cnf ib_logfile0 localhost.localdomain.err mysql_upgrade_info test
ibdata1 ib_logfile1 mysql performance_schema
[root@localhost data]# rm -rf ibdata1
[root@localhost data]# rm -rf ib_logfile*[root@localhost data]# ls
auto.cnf localhost.localdomain.err mysql mysql_upgrade_info performance_schema test
重新启动数据库
# /usr/test/mysql-5.6.32-linux-glibc2.5-x86_64/bin/mysqld --defaults-file=/usr/test/mysql-5.6.32-linux-glibc2.5-x86_64/my.cnf &
并没有报错
启动过程中的日志信息如下:
# -- :: [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
-- :: [Note] /usr/test/mysql-5.6.-linux-glibc2.-x86_64/bin/mysqld (mysqld 5.6.) starting as process ...
-- :: [Note] Plugin 'FEDERATED' is disabled.
-- :: [Note] InnoDB: Using atomics to ref count buffer pool pages
-- :: [Note] InnoDB: The InnoDB memory heap is disabled
-- :: [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
-- :: [Note] InnoDB: Memory barrier is not used
-- :: [Note] InnoDB: Compressed tables use zlib 1.2.
-- :: [Note] InnoDB: Using Linux native AIO
-- :: [Note] InnoDB: Using CPU crc32 instructions
-- :: [Note] InnoDB: Initializing buffer pool, size = 128.0M
-- :: [Note] InnoDB: Completed initialization of buffer pool
-- :: [Note] InnoDB: The first specified data file ./ibdata1 did not exist: a new database to be created!
-- :: [Note] InnoDB: Setting file ./ibdata1 size to MB
-- :: [Note] InnoDB: Database physically writes the file full: wait...
-- :: [Note] InnoDB: Setting log file ./ib_logfile101 size to MB
-- :: [Note] InnoDB: Setting log file ./ib_logfile1 size to MB
-- :: [Note] InnoDB: Renaming log file ./ib_logfile101 to ./ib_logfile0
-- :: [Warning] InnoDB: New log files created, LSN=
-- :: [Note] InnoDB: Doublewrite buffer not found: creating new
-- :: [Note] InnoDB: Doublewrite buffer created
-- :: [Note] InnoDB: rollback segment(s) are active.
-- :: [Warning] InnoDB: Creating foreign key constraint system tables.
-- :: [Note] InnoDB: Foreign key constraint system tables created
-- :: [Note] InnoDB: Creating tablespace and datafile system tables.
-- :: [Note] InnoDB: Tablespace and datafile system tables created.
-- :: [Note] InnoDB: Waiting for purge to start
-- :: [Note] InnoDB: 5.6. started; log sequence number
-- :: [Note] Server hostname (bind-address): '*'; port:
-- :: [Note] IPv6 is available.
-- :: [Note] - '::' resolves to '::';
-- :: [Note] Server socket created on IP: '::'.
-- :: [Note] Event Scheduler: Loaded events
-- :: [Note] /usr/test/mysql-5.6.-linux-glibc2.-x86_64/bin/mysqld: ready for connections.
Version: '5.6.32' socket: '/data/mysql.sock' port: MySQL Community Server (GPL)
可见,在启动的过程中,MySQL会重建ibdata1和redo log。
登录mysql客户端,看之前创建的t1,t2是否能访问
# /usr/test/mysql-5.6.32-linux-glibc2.5-x86_64/bin/mysql -h127.0.0.1 -p123456 -uroot -P3310
mysql> use test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| t1 |
| t2 |
+----------------+
2 rows in set (0.00 sec) mysql> select * from t1;
ERROR 1146 (42S02): Table 'test.t1' doesn't exist
通过show tables能查看有t1表存在,但表中的具体内容则无法查看
同时,错误日志中输出以下信息
-- :: [Warning] InnoDB: Cannot open table test/t1 from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
将数据目录下的test目录中的t1,t2表的数据文件和表定义文件COPY到其它地方
[root@localhost test]# cd /data/test/
[root@localhost test]# ll
total
-rw-rw---- mysql mysql Aug : t1.frm
-rw-rw---- mysql mysql Aug : t1.ibd
-rw-rw---- mysql mysql Aug : t2.frm
-rw-rw---- mysql mysql Aug : t2.ibd
[root@localhost test]# mv * /backup/
[root@localhost test]# ls
[root@localhost test]# ll /backup/
total
-rw-rw---- mysql mysql Aug : t1.frm
-rw-rw---- mysql mysql Aug : t1.ibd
-rw-rw---- mysql mysql Aug : t2.frm
-rw-rw---- mysql mysql Aug : t2.ibd
登录客户端,创建t1和t2表,注意表结构和之前的必须保持一致
细心的童鞋会发现,下面的创表语句和刚开始的创表语句并不一样,列名不一致,这个其实是为了后续的测试
mysql> show tables;
Empty set (0.00 sec) mysql> create table t1(id_1 int,hiredate_1 datetime);
ERROR 1146 (42S02): Table 'test.t1' doesn't exist
明明已经手动移除了,为什么创建表的时候还报这个错误呢?
接下来,可先执行个drop table操作
mysql> drop table t1;
ERROR 1051 (42S02): Unknown table 'test.t1'
mysql> create table t1(id_1 int,hiredate_1 datetime);
Query OK, 0 rows affected (0.07 sec)
对于t2表,我们定义一个不同的表结构,看是否可行?
mysql> drop table t2;
ERROR 1051 (42S02): Unknown table 'test.t2'
mysql> create table t2(id_1 int);
Query OK, 0 rows affected (0.01 sec)
导出表空间
mysql> ALTER TABLE t1 DISCARD TABLESPACE;
Query OK, 0 rows affected (0.00 sec) mysql> ALTER TABLE t2 DISCARD TABLESPACE;
Query OK, 0 rows affected (0.00 sec)
这个时候,数据目录下的test目录下,数据文件没有了,只剩下了表结构文件
[root@localhost test]# ls
t1.frm t2.frm
导入表空间
首先对t1表进行测试
在这里,测试如下两种情况
1. 新的t1.frm+旧的t1.ibd
2. 旧的t1.frm+旧的t1.ibd
第一种情况
只是将t1表的数据文件COPY回来
[root@localhost test]# cp /backup/t1.ibd .
[root@localhost test]# chown mysql.mysql t1.ibd
导入t1表的表空间
mysql> ALTER TABLE t1 IMPORT TABLESPACE;
Query OK, 0 rows affected, 1 warning (0.21 sec) mysql> show warnings;
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1810 | InnoDB: IO Read error: (2, No such file or directory) Error opening './test/t2.cfg', will attempt to import without schema verification |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
查看t1表是否能访问
mysql> select * from t1;
+------+---------------------+
| id_1 | hiredate_1 |
+------+---------------------+
| 1 | 2016-08-18 17:45:02 |
| 2 | 2016-08-18 17:45:02 |
+------+---------------------+
2 rows in set (0.00 sec) mysql> flush table t1;
Query OK, 0 rows affected (0.00 sec) mysql> select * from t1;
+------+---------------------+
| id_1 | hiredate_1 |
+------+---------------------+
| 1 | 2016-08-18 17:45:02 |
| 2 | 2016-08-18 17:45:02 |
+------+---------------------+
2 rows in set (0.00 sec)
喔,确实能访问,注意观察,表的列名与新的创表语句保持一致。
在这里之所以使用flush table操作,是为了刷新内存中的表定义。
下面看看t1的第二种情况,旧的t1.frm+旧的t1.ibd
mysql> ALTER TABLE t1 DISCARD TABLESPACE;
Query OK, 0 rows affected (0.00 sec)
[root@localhost test]# cp /backup/t1.frm .
cp: overwrite `./t1.frm'? y
[root@localhost test]# cp /backup/t1.ibd .
[root@localhost test]# chown mysql.mysql t1.frm
[root@localhost test]# chown mysql.mysql t1.ibd
mysql> ALTER TABLE t1 import TABLESPACE;
Query OK, 0 rows affected, 1 warning (0.04 sec) mysql> select * from t1;
+------+---------------------+
| id_1 | hiredate_1 |
+------+---------------------+
| 1 | 2016-08-18 17:45:02 |
| 2 | 2016-08-18 17:45:02 |
+------+---------------------+
2 rows in set (0.00 sec) mysql> flush table t1;
Query OK, 0 rows affected (0.00 sec) mysql> select * from t1;
+------+---------------------+
| id | hiredate |
+------+---------------------+
| 1 | 2016-08-18 17:45:02 |
| 2 | 2016-08-18 17:45:02 |
+------+---------------------+
2 rows in set (0.00 sec)
第一次查询的时候还是新的列名,对表进行flush后,就恢复到原来的列名了。
下面来看看t2表的导入情况
因为t2表的表结构发生了改变,在这里,也是测试如下两种情况
1. 新的t2.frm+旧的t2.ibd
2. 旧的t2.frm+旧的t2.ibd
首先,只是导入t2表的数据文件
[root@localhost test]# cp /backup/t2.ibd .
[root@localhost test]# ll
total
-rw-rw---- mysql mysql Aug : t1.frm
-rw-r----- mysql mysql Aug : t1.ibd
-rw-rw---- mysql mysql Aug : t2.frm
-rw-r----- root root Aug : t2.ibd
[root@localhost test]# chown mysql.mysql t2.ibd
导入t2表的表空间进行测试
mysql> ALTER TABLE t2 import TABLESPACE;
Query OK, 0 rows affected, 1 warning (0.03 sec) mysql> select * from t2;
+------+
| id_1 |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec) mysql> flush table t2;
Query OK, 0 rows affected (0.00 sec) mysql> select * from t2;
+------+
| id_1 |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec)
从结果可以看出,只能读出第一列。
下面测试第二种情况,旧的t2.frm和t2.ibd
mysql> ALTER TABLE t2 DISCARD TABLESPACE;
Query OK, 0 rows affected (0.06 sec)
[root@localhost test]# rm -rf t2.frm
[root@localhost test]# cp /backup/t2.frm .
[root@localhost test]# cp /backup/t2.ibd .
[root@localhost test]# chown mysql.mysql t2.frm
[root@localhost test]# chown mysql.mysql t2.ibd
mysql> ALTER TABLE t2 import TABLESPACE;
Query OK, 0 rows affected, 1 warning (0.09 sec) mysql> select * from t2;
+------+
| id_1 |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec) mysql> flush table t2;
Query OK, 0 rows affected (0.00 sec) mysql> select * from t2;
ERROR 1146 (42S02): Table 'test.t2' doesn't exist
在重新刷新后,就出现错误了,个人感觉,这个和系统表空间中的数据字典信息有关。
实际上,后续还测试了一下,如果将hiredate的列定义为varchar,则无论是使用之前的frm文件还是之后的,在导入表空间,进行查询时,数据库直接挂掉。
mysql> create table t1(id int,hiredate varchar(10));
Query OK, 0 rows affected (0.05 sec) mysql> ALTER TABLE t1 DISCARD TABLESPACE;
Query OK, 0 rows affected (0.00 sec) mysql> ALTER TABLE t1 import TABLESPACE;
Query OK, 0 rows affected, 1 warning (0.03 sec) mysql> select * from t1;
ERROR 2013 (HY000): Lost connection to MySQL server during query
结论
经过上面的一系列测试,可以看到
1. 使用可传输表空间,可以解决在删除ibdata1和ib_logfile的情况下恢复MySQL数据库,当然,本文测试的前提是数据库正常关闭下删除的ibdata1和ib_logfile。
2. 使用可传输表空间,建议新建表的表结构和原来的表结构完全一致,同时,在导入表空间前,只需COPY回原来的数据文件,即ibd。
事实上,在数据库正常关闭下删除ibdata1,会导致mysql库中的以下几张表无法访问
mysql> select table_name from information_schema.tables where table_schema='mysql' and engine='innodb';
+----------------------+
| table_name |
+----------------------+
| innodb_index_stats |
| innodb_table_stats |
| slave_master_info |
| slave_relay_log_info |
| slave_worker_info |
+----------------------+
5 rows in set (0.00 sec) mysql> select * from mysql.innodb_index_stats;
ERROR 1146 (42S02): Table 'mysql.innodb_index_stats' doesn't exist
mysql> select * from mysql.innodb_table_stats;
ERROR 1146 (42S02): Table 'mysql.innodb_table_stats' doesn't exist
mysql> select * from mysql.slave_master_info;
ERROR 1146 (42S02): Table 'mysql.slave_master_info' doesn't exist
mysql> select * from mysql.slave_relay_log_info;
ERROR 1146 (42S02): Table 'mysql.slave_relay_log_info' doesn't exist
mysql> select * from mysql.slave_worker_info;
ERROR 1146 (42S02): Table 'mysql.slave_worker_info' doesn't exist
同时,错误日志中报如下信息
-- :: [Warning] InnoDB: Cannot open table mysql/innodb_index_stats from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
-- :: [Warning] InnoDB: Cannot open table mysql/innodb_table_stats from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
-- :: [Warning] InnoDB: Cannot open table mysql/slave_master_info from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
-- :: [Warning] InnoDB: Cannot open table mysql/slave_relay_log_info from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
-- :: [Warning] InnoDB: Cannot open table mysql/slave_worker_info from the internal data dictionary of InnoDB though the .frm file for the table exists. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how you can resolve the problem.
要解决这个问题,只能重建这些表。
参考
1. http://dev.mysql.com/doc/refman/5.6/en/tablespace-copying.html
2. http://dba.stackexchange.com/questions/48166/cannot-open-table-mysql-innodb-index-stats
如何在删除ibdata1和ib_logfile的情况下恢复MySQL数据库的更多相关文章
- SQL Server 在缺少文件组的情况下如何还原数据库
SQL Server 在缺少文件组的情况下如何还原数据库 一.背景 我有一个A库,由于a,b两张表的数据量比较大,所以对表进行分区:在把A库迁移到一个新的集群上去,我只备份了A库的主分区过去进行还原为 ...
- 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 MySQL 数据库,又插入了一条数据,此时 id 是几?如何获取当前数据库版本?
一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 MySQL 数据库,又插入了一条数据,此时 id 是几? 一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysq ...
- 恢复MySQL数据库删除的数据
在日常运维工作中,对于数据库的备份是至关重要的!数据库对于网站的重要性使得我们对 MySQL 数据库的管理不容有失!然而是人总难免会犯错误,说不定哪天大脑短路了,误操作把数据库给删除了,怎么办? 下面 ...
- Oracle备份恢复之无备份情况下恢复undo表空间
UNDO表空间存储着DML操作数据块的前镜像数据,在数据回滚,一致性读,闪回操作,实例恢复的时候都可能用到UNDO表空间中的数据.如果在生产过程中丢失或破坏了UNDO表空间,可能导致某些事务无法回滚, ...
- Entity framework 意外删除了表,如何在不影响其它表的情况下恢复回来
关于EntityFramework数据迁移原理 查询数据库的表"__MigrationHistory",遍历代码库的Migrations文件夹下的所有文件,如果文件不在__Migr ...
- 无shell情况下的mysql远程mof提权利用方法详解
扫到一个站的注入<ignore_js_op> 在havij中得到mysql数据库中mysql库保存的数据库密码:<ignore_js_op> 有时候发现1.15版的还是最好用, ...
- 怎样使用PL/SQL在不安装oracle 客户端的情况下使用oracle数据库
在网上查了好多这方面的例子,但是似乎说的都不准确,在咨询朋友后终于实现了本机不安装oracle 的情况下,在windows系统上实现连接服务器上的数据库,现在贴出来与大家共享. 首先,我们需要一个PL ...
- 2019年春季学期第二周作业 基础作业 请在第一周作业的基础上,继续完成:找出给定的文件中数组的最大值及其对应的最小下标(下标从0开始)。并将最大值和对应的最小下标数值写入文件。 输入: 请建立以自己英文名字命名的txt文件,并输入数组元素数值,元素值之间用逗号分隔。 输出 在不删除原有文件内容的情况下,将最大值和对应的最小下标数值写入文件
~~~ include<stdio.h> include<stdlib.h> int main() { FILE*fp; int i=0,max=0,j=0,maxb=0; i ...
- SSD磁盘,CPU居高不下,高并发的情况下,是不是mysql解析器耗费的cpu资源高?
你看看我做的实验,这个user表是300多W纪录,普通磁盘下,消耗时间最多的是Copy to tmp table 0.81秒,当然在ssd下,这个可以减少很多很多的,第二高就是sending data ...
随机推荐
- js中参数不对应问题
因为js是一种弱类型的编程语言,对数据类型的要求没有其他编程语言的要求严格,所以在定义函数的时候不需要像java和C#一样对其传入参数的类型进行定义.那么传入参数的个数有没有影响呢?今天小猪就做了个实 ...
- setAttribute()
●节点分为不同的类型:元素节点.属性节点和文本节点等. ●getElementById()方法将返回一个对象,该对象对应着文档里的一个特定的元素节点. ●getElementsByTagNam ...
- 【.net 深呼吸】程序集的热更新
当一个程序集被加载使用的时候,出于数据的完整性和安全性考虑,程序集文件(在99.9998%的情况下是.dll文件)会被锁定,如果此时你想更新程序集(实际上是替换dll文件),是不可以操作的,这时你得把 ...
- .NET Core采用的全新配置系统[9]: 为什么针对XML的支持不够好?如何改进?
物理文件是我们最常用到的原始配置的载体,最佳的配置文件格式主要由三种,它们分别是JSON.XML和INI,对应的配置源类型分别是JsonConfigurationSource.XmlConfigura ...
- Hawk 4.7 单步调试
单步调试的意义 已经编写的工作流,可能会因为某些外界环境的变化而出错,此时需要排除错误,我们可以使用单步调试. 单步调试的本质,相当于只使用前n个模块,这样就能看到每个步骤下,流的改变. 例子 还是上 ...
- PHP好用但又容易忽略的小知识
1.PHP函数之判断函数是否存在 当我们创建了自定义函数,并且了解了可变函数的用法,为了确保程序调用的函数是存在的,经常会先使用function_exists判断一下函数是否存在.同样的method_ ...
- 小兔JS教程(三)-- 彻底攻略JS回调函数
这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...
- winform 窗体圆角设计
网上看到的很多winform窗体圆角设计代码都比较累赘,这里分享一个少量代码就可以实现的圆角.主要运用了System.Drawing.Drawing2D. 效果图 代码如下. private void ...
- 【C#公共帮助类】 ToolsHelper帮助类
这个帮助类,目前我们只用到了两个,我就先更新这两个,后面有用到的,我会继续更新这个Helper帮助类 在Tools.cs中 有很多方法 跟Utils里是重复的,而且Utils里的方法更加新一点,大家可 ...
- JAVA面试题
在这里我将收录我面试过程中遇到的一些好玩的面试题目 第一个面试题:ABC问题,有三个线程,工作的内容分别是打印出"A""B""C",需要做的 ...