资讯专栏INFORMATION COLUMN

MySQL维护之--表损坏如何挽回

IT那活儿 / 2315人阅读
MySQL维护之--表损坏如何挽回
点击上方“IT那活儿”公众号,关注后了解更多内容,不管IT什么活儿,干就完了!!!

  

在我们MySQL数据库维护工作中极力要避免的突发状况里面,表数据损坏无疑是一种非常糟糕的情况

然而在实际情况中,有时候这些突发状况可能因为各种各样的因素还是残酷地需要我们直面处理。当这些突发状况发生时,也不要太过沮丧,如果我们能够冷静专业的面对,也许转机就在前方。

下面来针对两种有代表性的情况做一个模拟。


状况一:系统表损坏

如果发生了数据库系统表损坏,首先登录备库查看系统表是否正常(如果有备库的话),大多数情况下,备库是正常的,这个时候我们可以进行VIP切换,然后再使用备库备份重建原主库。
当然,情况也可能更糟糕,也就是主备库系统表同时损坏,也不要慌,我们可以尝试使用/usr/local/mysql/share下.sql脚本文件进行重建步骤如下
1. 模拟系统表损坏,进入…data/mysql/下打开文件编辑,清空文件
#/dev/null > innodb_index_stats.frm
#ll innodb_index_stats.frm
-rw-r----- 1 mysql mysql 0 Mar 24 08:41 innodb_index_stats.frm

2. 重启动数据库,无法正常启动

# sh shutdown.sh
Enter password:
# sh startup.sh
#sh login.sh
Enter password:
ERROR 2002 (HY000): Cant connect to local MySQL server through socket /data/mysql/db_order/mysql.sock (2)

3. 出现错误日志

2021-03-24T08:43:05.378517-05:00 0 [ERROR] InnoDB: The size of tablespace file ./mysql/innodb_index_stats.ibd is only 49674, should be at least 65536!
2021-03-24 08:43:05 0x7fc7430a4740 InnoDB: Assertion failure in thread 140493799966528 in file fil0fil.cc line 793
InnoDB: We intentionally generate a memory trap.

4. 修改参数文件,添加innodb_force_recovery = 6,强制启动数据库,存在丢失少量数据风险

# sh startup.sh
#sh login.sh #此时,正常启动
Enter password:
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 3
Server version: 5.7.25-log Source distribution
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type help; or h for help. Type c to clear the current
input statement.

5. 修改参数文件,还原innodb_force_recovery = 0,再重新启动

#sh shutdown.sh
#sh startup.sh
mysql> use mysql;

6. 删除损坏表

mysql> drop table innodb_index_stats;
ERROR 1051 (42S02): Unknown table mysql.innodb_index_stats
mysql> drop table if exists innodb_index_stats;
Query OK, 0 rows affected, 1 warning (1.07 sec)
# rm innodb_index_stats.frm
# rm innodb_index_stats.ibd

7. 进入系统目录,查看创建系统表脚本mysql_system_tables.sql

# cd /usr/local/mysql/share/
# ls *.sql
fill_help_tables.sql install_rewriter.sql mysql_sys_schema.sql mysql_system_tables.sql uninstall_rewriter.sql
innodb_memcached_config.sql mysql_security_commands.sql mysql_system_tables_data.sql mysql_test_data_timezone.sql
# cat *.sql|grep innodb_index_stats
SET @create_innodb_index_stats="CREATE TABLE IF NOT EXISTS innodb_index_stats (
SET @str=IF(@have_innodb <> 0, @create_innodb_index_stats, "SET @dummy = 0");


8. 登录数据库,进行表结构创建
mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with –A


9. 再次进行重启动数据库,加载数据
mysql> select count(*) from innodb_index_stats;
+----------+
| count(*) |
+----------+
| 13 |
+----------+
1 row in set (0.00 sec)
至此,系统表恢复成功。

状况二:数据表损坏(InnoDB)

如果数据表损坏,同样首先要登录备库查看是否正常,如果备库正常,进行VIP切换,然后自然可以通过备库的备份来重建原主库。
然而,如果主备库数据表同时损坏,那么想完全找回全部的数据已经很难了,只能尽量降低损失,最大限度的恢复数据。
可以通过设定参数innodb_force_recovery级别,选择尽可能低的丢失数据风险,启动数据库后,进行数据表的恢复。
模拟过程如下:
1. InnoDB表文件损坏恢复方法
2. 模拟表数据文件.ibd损坏,打开tt.idb文件,删除任一个字符后保存,关闭数据库后,启动
mysql> select count(*) from tt;
+----------+
| count(*) |
+----------+
| 407 | #损坏前数据笔数407
+----------+
1 row in set (0.00 sec)
#cd ./data/htest
#vi tt.ibd #打开删除任一字符
#sh shutdown.sh
#sh startup.sh

3. 无法登录数据库,log出现错误

#sh login.sh

Enter password:
ERROR 2002 (HY000): Cant connect to local MySQL server
through socket /data/mysql/db_order/mysql.sock (2)

#
cat mysql.err|more

2021-03-25T08:34:42.683624-05:00 0 [ERROR] InnoDB: Database
page corruption on disk or a failed file read of page [page
id: space=124, page number=5]. You may have to recover from
a backup.


4. 尝试备份损坏表,无法连接
# mysqldump -uroot -psystem -S 
/data/mysql/db_order/mysql.sock --single-transaction --
default-character-set=utf8 --set-gtid-purged=off --add-drop-
table --triggers --events --routines htest tt>tt.sql

mysqldump: [Warning] Using a password on the command line
interface can be insecure.

mysqldump: Got error: 2002: Cant connect to local MySQL
server through socket
/data/mysql/db_order/mysql.sock (2)
when trying to connect
5. 参数文件添加innodb_force_recovery = 4,强制启动数据库
#sh login.sh
Enter password:
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 3
Server version: 5.7.25-log Source distribution
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type help; or h for help. Type c to clear the current input statement.
mysql> use htest;
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> desc tt;
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
|
 TABLE_SCHEMA | varchar(64) | YES | | NULL | |
| TABLE_NAME | varchar(64) | YES |     | NULL |       |
|
 CREATE_TIME | datetime | YES | | NULL | |
+--------------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
6. 进行损坏表的备份,只能备份出正常数据
#mysqldump -uroot -psystem -S /data/mysql/db_order/mysql.sock --single-transaction --default-character-set=utf8 --set-gtid-purged=off --add-drop-table --triggers --events --routines htest tt>tt.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
mysqldump: Error 2013: Lost connection to MySQL server during query when dumping table `tt` at row: 339
[mysql@mysqltest1 bin]$ ll
total 32
-rw-r--r-- 1 mysql mysql 19304 Mar 25 08:51 tt.sql

7. 删除损坏表

mysql> drop table tt;
Query OK, 0 rows affected (1.39 sec)
8. 将参数innodb_force_recovery = 4清除,重启动数据库后,进行数据导入
mysql> show tables;
Empty set (0.00 sec)
mysql> source tt.sql;
Query OK, 0 rows affected (0.00 sec)
...
Query OK, 339 rows affected (0.08 sec)
Records: 339 Duplicates: 0 Warnings: 0
mysql> select count(*) from tt;
+----------+
| count(*) |
+----------+
| 339 | #相较407笔减少68笔数据,存在少量数据丢失风险
+----------+
1 row in set (0.00 sec)

需要说明的是:

innodb_force_recovery = 4代表相对比较安全,只有一些在损坏的多带带页面上的数据会丢失。

如果是innodb_force_recovery =6 ,数据库页将被留在一个陈旧的状态,这个状态反过来可以引发对B 树和其它数据库结构的更多破坏。


本文作者:沈亚威(上海新炬王翦团队)

本文来源:“IT那活儿”公众号

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/129369.html

相关文章

  • MySQL 复制 - 性能与扩展性的基石 3:常见问题及解决方案

    摘要:问题原因非正常关机导致没有把数据及时的写入硬盘。丢失的临时表临时表和基于语句的复制方式不相容。如果备库崩溃或者正常关闭,任何复制线程拥有的临时表都会丢失。临时表的特性只对创建临时表的连接可见。 主备复制过程中有很大可能会出现各种问题,接下来我们就讨论一些比较普遍的问题,以及当遇到这些问题时,如何解决或者预防问题发生。 1 数据损坏或丢失 问题描述:服务器崩溃、断电、磁盘损坏、内存或网络...

    canopus4u 评论0 收藏0
  • MySQL 复制 - 性能与扩展性的基石 3:常见问题及解决方案

    摘要:问题原因非正常关机导致没有把数据及时的写入硬盘。丢失的临时表临时表和基于语句的复制方式不相容。如果备库崩溃或者正常关闭,任何复制线程拥有的临时表都会丢失。临时表的特性只对创建临时表的连接可见。 主备复制过程中有很大可能会出现各种问题,接下来我们就讨论一些比较普遍的问题,以及当遇到这些问题时,如何解决或者预防问题发生。 1 数据损坏或丢失 问题描述:服务器崩溃、断电、磁盘损坏、内存或网络...

    haobowd 评论0 收藏0

发表评论

0条评论

IT那活儿

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<