前言:

MySQL 逻辑备份工具最常用的就是 mysqldump 了,一般我们都是备份整个实例或部分业务库。不清楚你有没有做过恢复,恢复场景可能就比较多了,比如我想恢复某个库或某个表等。那么如何从全备中恢复单库或单表,这其中又有哪些隐藏的坑呢?这篇文章我们一起来看下。

1.如何恢复单库或单表

前面文章有介绍过 MySQL 的备份与恢复。可能我们每个数据库实例中都不止一个库,一般备份都是备份整个实例,但恢复需求又是多种多样的,比如说我想只恢复某个库或某张表,这个时候应该怎么操作呢?

如果你的实例数据量不大,可以在另外一个环境恢复出整个实例,然后再单独备份出所需库或表用来恢复。不过这种方法不够灵活,并且只适用数据量比较少的情况。

其实从全备中恢复单库还是比较方便的,有个 --one-database 参数可以指定单库恢复,下面来具体演示下:

# 查看及备份所有库

mysql> show databases;

+--------------------+

| Database |

+--------------------+

| information_schema |

| mysql |

| performance_schema |

| sbtest |

| sys |

| testdb |

| testdb2 |

+--------------------+

mysqldump -uroot -pxxxx -R -E --single-transaction --all-databases > all_db.sql

# 删除testdb库 并进行单库恢复

mysql> drop database testdb;

Query OK, 36 rows affected (2.06 sec)

# 貌似恢复前 testdb库不存在的话要手动新建

mysql -uroot -pxxxx --one-database testdb < all_db.sql

除了上述方法外,恢复单库或单表还可以采用手动筛选的方法。这个时候 Linux 下大名鼎鼎的 sed 和 grep 命令就派上用场了,我们可以利用这两个命令从全备中筛选出单库或单表的语句,筛选方法如下:

# 从全备中恢复单库

sed -n '/^-- Current Database: `testdb`/,/^-- Current Database: `/p' all_db.sql > testdb.sql

# 筛选出单表语句

cat all_db.sql | sed -e '/./{H;$!d;}' -e 'x;/CREATE TABLE `test_tb`/!d;q' > /tmp/test_tb_info.sql

cat all_db.sql | grep --ignore-case 'insert into `test_tb`' > /tmp/test_tb_data.sql

2.小心有坑

对于上述手动筛选来恢复单库或单表的方法,看起来简单方便,其实隐藏着一个小坑,下面我们来具体演示下:

# 备份整个实例

mysqldump -uroot -pxxxx -R -E --single-transaction --all-databases > all_db.sql

# 手动备份下test_tb 然后删除test_tb

mysql> create table test_tb_bak like test_tb;

Query OK, 0 rows affected (0.03 sec)

mysql> insert into test_tb_bak select * from test_tb;

Query OK, 4 rows affected (0.02 sec)

Records: 4 Duplicates: 0 Warnings: 0

mysql> drop table test_tb;

Query OK, 0 rows affected (0.02 sec)

# 从全备中筛选test_db建表及插数据语句

cat all_db.sql | sed -e '/./{H;$!d;}' -e 'x;/CREATE TABLE `test_tb`/!d;q' > test_tb_info.sql

cat all_db.sql | grep --ignore-case 'insert into `test_tb`' > test_tb_data.sql

# 查看得到的语句 貌似没问题

cat test_tb_info.sql

DROP TABLE IF EXISTS `test_tb`;

/*!40101 SET @saved_cs_client = @@character_set_client */;

/*!40101 SET character_set_client = utf8 */;

CREATE TABLE `test_tb` (

`inc_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',

`col1` int(11) NOT NULL,

`col2` varchar(20) DEFAULT NULL,

`col_dt` datetime DEFAULT NULL,

`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',

PRIMARY KEY (`inc_id`)

) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='测试表';

/*!40101 SET character_set_client = @saved_cs_client */;

cat test_tb_data.sql

INSERT INTO `test_tb` VALUES (1,1001,'dsfs','2020-08-04 12:12:36','2020-09-17 06:19:27','2020-09-17 06:19:27'),

(2,1002,'vfsfs','2020-09-04 12:12:36','2020-09-17 06:19:27','2020-09-17 06:19:27'),

(3,1003,'adsfsf',NULL,'2020-09-17 06:19:27','2020-09-17 06:19:27'),

(4,1004,'walfd','2020-09-17 14:19:27','2020-09-17 06:19:27','2020-09-18 07:52:13');

# 执行恢复单表操作

mysql -uroot -pxxxx testdb < test_tb_info.sql

mysql -uroot -pxxxx testdb < test_tb_data.sql

# 查看恢复数据 并和备份表比对

mysql> select * from test_tb;

+--------+------+--------+---------------------+---------------------+---------------------+

| inc_id | col1 | col2 | col_dt | create_time | update_time |

+--------+------+--------+---------------------+---------------------+---------------------+

| 1 | 1001 | dsfs | 2020-08-04 12:12:36 | 2020-09-17 06:19:27 | 2020-09-17 06:19:27 |

| 2 | 1002 | vfsfs | 2020-09-04 12:12:36 | 2020-09-17 06:19:27 | 2020-09-17 06:19:27 |

| 3 | 1003 | adsfsf | NULL | 2020-09-17 06:19:27 | 2020-09-17 06:19:27 |

| 4 | 1004 | walfd | 2020-09-17 14:19:27 | 2020-09-17 06:19:27 | 2020-09-18 07:52:13 |

+--------+------+--------+---------------------+---------------------+---------------------+

4 rows in set (0.00 sec)

mysql> select * from test_tb_bak;

+--------+------+--------+---------------------+---------------------+---------------------+

| inc_id | col1 | col2 | col_dt | create_time | update_time |

+--------+------+--------+---------------------+---------------------+---------------------+

| 1 | 1001 | dsfs | 2020-08-04 12:12:36 | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 |

| 2 | 1002 | vfsfs | 2020-09-04 12:12:36 | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 |

| 3 | 1003 | adsfsf | NULL | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 |

| 4 | 1004 | walfd | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 | 2020-09-18 15:52:13 |

+--------+------+--------+---------------------+---------------------+---------------------+

4 rows in set (0.00 sec)

如果你仔细观察的话,会发现恢复出来的数据有问题,貌似时间不太对,你再仔细看看,是不是有的时间差了8小时!详细探究下来,我们发现 timestamp 类型字段的时间数据恢复有问题,准确来讲备份文件中记录的是0时区,而我们系统一般采用东八区,所以才会出现误差8小时的问题。

那么你会问了,为什么全部恢复不会出问题呢?问的好,我们看下备份文件就知道了。

# 备份文件开头

-- MySQL dump 10.13 Distrib 5.7.23, for Linux (x86_64)

--

-- Host: localhost Database:

-- ------------------------------------------------------

-- Server version 5.7.23-log

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;

/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;

/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;

/*!40101 SET NAMES utf8 */;

/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;

/*!40103 SET TIME_ZONE='+00:00' */;

注意上面两行

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;

/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;

/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;

/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

# 备份文件结尾

/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;

/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;

/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;

/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2020-09-18 15:56:40

仔细看备份文件,你会发现 mysqldump 备份出来的文件中,首先会将会话时区改为0,结尾处再改回原时区。这就代表着,备份文件中记录的时间戳数据都是以0时区为基础的。如果直接执行筛选出的SQL,就会造成0时区的时间戳插入的东八区的系统中,显然会造成时间相差8小时的问题。

看到这里,不知道你是否看懂了呢,可能有过备份恢复经验的同学好理解些。解决上述问题的方法也很简单,那就是在执行SQL文件前,更改当前会话时区为0,再次来演示下:

# 清空test_db表数据

mysql> truncate table test_tb;

Query OK, 0 rows affected (0.02 sec)

# 文件开头增加时区声明

vim test_tb_data.sql

set session TIME_ZONE='+00:00';

INSERT INTO `test_tb` VALUES (1,1001,'dsfs','2020-08-04 12:12:36','2020-09-17 06:19:27','2020-09-17 06:19:27'),

(2,1002,'vfsfs','2020-09-04 12:12:36','2020-09-17 06:19:27','2020-09-17 06:19:27'),

(3,1003,'adsfsf',NULL,'2020-09-17 06:19:27','2020-09-17 06:19:27'),

(4,1004,'walfd','2020-09-17 14:19:27','2020-09-17 06:19:27','2020-09-18 07:52:13');

# 执行恢复并比对 发现数据正确

mysql> select * from test_tb;

+--------+------+--------+---------------------+---------------------+---------------------+

| inc_id | col1 | col2 | col_dt | create_time | update_time |

+--------+------+--------+---------------------+---------------------+---------------------+

| 1 | 1001 | dsfs | 2020-08-04 12:12:36 | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 |

| 2 | 1002 | vfsfs | 2020-09-04 12:12:36 | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 |

| 3 | 1003 | adsfsf | NULL | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 |

| 4 | 1004 | walfd | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 | 2020-09-18 15:52:13 |

+--------+------+--------+---------------------+---------------------+---------------------+

4 rows in set (0.00 sec)

mysql> select * from test_tb_bak;

+--------+------+--------+---------------------+---------------------+---------------------+

| inc_id | col1 | col2 | col_dt | create_time | update_time |

+--------+------+--------+---------------------+---------------------+---------------------+

| 1 | 1001 | dsfs | 2020-08-04 12:12:36 | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 |

| 2 | 1002 | vfsfs | 2020-09-04 12:12:36 | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 |

| 3 | 1003 | adsfsf | NULL | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 |

| 4 | 1004 | walfd | 2020-09-17 14:19:27 | 2020-09-17 14:19:27 | 2020-09-18 15:52:13 |

+--------+------+--------+---------------------+---------------------+---------------------+

4 rows in set (0.00 sec)

总结:

我们在网络中很容易搜索出恢复单库或单表的方法,大多都有提到上述利用 sed 、grep 命令来手动筛选的方法。但大部分文章都未提及可能出现的问题,如果你的表字段有timestamp 类型,用这种方法要格外注意。无论面对哪种恢复需求,我们都要格外小心,不要造成越恢复越糟糕的情况,最好有个空实例演练下,然后再进行恢复。

以上就是MySQL如何恢复单库或单表,以及可能遇到的坑的详细内容,更多关于MySQL 恢复单库或单表的资料请关注脚本之家其它相关文章!

mysql如何恢复单表_MySQL如何恢复单库或单表,以及可能遇到的坑相关推荐

  1. mysql 导入单个表_MySQL 备份恢复(导入导出)单个 innodb表

    MySQL 备份恢复单个innodb表呢,对于这种恢复我们我们很多朋友都不怎么了解了,下面一起来看一篇关于MySQL 备份恢复单个innodb表的教程 在实际环境中,时不时需要备份恢复单个或多个表(注 ...

  2. mysql 只开放某个表_MySQL只恢复某个库或某张表

    在Mysqldump官方工具中,如何只恢复某个库呢? 全库备份 [root@HE1 ~]#mysqldump -uroot -p --single-transaction -A --master-da ...

  3. 如何用mysql创建orders表_MySQL学习十四创建和操纵表

    摘要: 本篇博客仅作为笔记,如有侵权,请联系,立即删除(网上找博客学习,然后手记笔记,因纸质笔记不便保存,所以保存到网络笔记). 本博讲述表的创建.更改和删除的基本知识. 一.创建表 MySQL不仅用 ...

  4. mysql显示表的所有列车_MySQL中查看当前数据库的所有表

    关键词 MySQL数据库 表 摘要 本文介绍在MySQL数据库中,如何列出并查看当前数据库的所有表. 本文介绍在MySQL数据库中,如何列出并查看当前数据库的所有表. 我们创建一个数据库之后,数据库里 ...

  5. 虚拟机mysql创建一个表_MySQL:创建、修改和删除表

    其实对很多人来说对于SQL语句已经忘了很多,或者说是不懂很多,因为有数据库图形操作软件,方便了大家,但是我们不能忘记最根本的东西,特别是一些细节上的东西,可能你用惯了Hibernate,不用写SQL语 ...

  6. 怎样知道mysql的驱动是什么_MySQL连接查询到底什么是驱动表?看了这里你应该就明白了...

    作者:阿伟~ 链接:https://www.cnblogs.com/sy270321/p/12760211.html 准备我们需要的表结构和数据 两张表 studnet(学生)表和score(成绩)表 ...

  7. mysql数据库查询全部信息_mysql 查询怎么获取数据库下所有表的信息?

    展开全部 如果说你不知道有多少个 cx_1,,cx_100这种的表的话, 貌似直接SQL语句试了一下没法查的好像, 我建议是 结合PHP代码,先查323131333532363134313032313 ...

  8. 怎么查找表_MySQL索引是怎么支撑千万级表的快速查找?

    前言 在 MySQL 官方提到,改善操作性能的最佳方法 SELECT在查询中测试的一个或多个列上创建索引.索引条目的作用类似于指向表行的指针,从而使查询可以快速确定哪些行与WHERE子句中的条件匹配, ...

  9. delete 会不会锁表_MySQL的insert into select 引发锁表

    上周五HaC我要上线,有一个脚本需要执行,执行前需要备份一个表. 运维大佬:"这个表的备份为什么要这么久,,??" 1秒过去了--2秒过去了-- 期间运营反馈系统出现大量订单超时情 ...

最新文章

  1. CodeForces - 1364C Ehab and Prefix MEX(贪心+构造)
  2. modal vue 关闭_Vue弹出框的优雅实践
  3. AsyncTask异步加载的源码分析与实现实例
  4. 求第i个小的元素 时间复杂度O(n)
  5. java 蓝桥杯算法训练 每月的天数(题解)
  6. Spring mvc Interceptor 解决Session超时配置流程
  7. 【毕业设计】JSP网络在线考试系统设计(源代码+论文)
  8. 贺利坚老师汇编课程27笔记(一):段前缀的使用
  9. python写出租车计费系统_出租车自动计费器设计(课程设计报告模板)
  10. Android 与Js通信报Java Exception was raised during method Invocation错误,引发的惨案
  11. Unity一般工程升级到HDRP
  12. jQuery的promise异步模式
  13. 科研论文如何讲好“故事”
  14. JavaSE(二)-抽象类
  15. 基于onenet的开关定位接收消息的APP设计
  16. c语言组建怎样变成编译,c语言编译【处理流程】
  17. 对于自我的反省 - 对底层人民认知产生的商业思考
  18. 论信息系统项目的需求管理
  19. Oracle语言和字符集设置
  20. 已知三点坐标求三角形面积等几何图形学问题算法

热门文章

  1. 深入理解散列函数和散列表
  2. 【SpringBoot】72、SpringBoot中接入轻量级分布式日志框架Graylog
  3. ossbrowser
  4. Linux命令之dos2unix
  5. 京东智能云APP可用来做什么?
  6. 用keil语言定义c51,51单片机Keil C51的使用(C语言)
  7. allgro pcb铜皮编辑_关于修割铜皮 - Cadence allegro PCB 教程
  8. 判断处理器是大端模式还是小端模式
  9. excel单元格斜杠拆分上下打字
  10. liquibase基本使用