数据库恢复方案
目录
- 1. 背景
- 2. 备份方式分析
- 3. 恢复方案
- 3.1. 第一种
- 3.2. 第二种
- 3.3. 第三种
- 3.4. 第四种
- 4. 手工恢复
1. 背景
我们来假设一个场景。
你是否适用 mysqldump 每隔一段时间备份一次数据库,每个备份一个数据文件。
公司决策你是不是因为数据持续增加,有些数据已经不会再查询,会删除旧的历史数据。
有时公司突然说要恢复历史数据,有可能全补回复,有可能部分恢复。
你将怎么做?
2. 备份方式分析
首先看看备份方式,你是不是采用这种方法备份
我使用一串数字表述数据库数据递增情况,数据的增长变化
垂直轴表示备份时间轴
最常见的备份方法,完全备份
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...
|.......| 第一次备份
|.................| 第二次备份
|...........................| 第三次备份
|......................................| 第四次备份
|................................................| 第五次备份
下面这种备份方式也比较常见,这种方式很有规律。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...
|.......| 第一次备份
|..........| 删除上一次以备份内容,第二次备份
|..........| 删除上一次以备份内容,第三次备份数据库
|..........| 删除上一次以备份内容,第四次备份
|.........| 删除上一次以备份内容,第五次备份
更复杂的情况,无规律可循
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...
|.......| 第一次备份
|..................| 第二次备份
|......................| 删除一部分数据后同时做第三次备份数据库
|......................| 又删除一部分数据,第四次备份
|.............................| 第五次备份,没有删除数据
|......................................| 第六次备份,依然没有删除数据
|..........................| 删除很多数据,第七次备份
以此类推,删除原因有多种,如空间不足,改善查询性能...等等
最杂的情况,无规律可循,同时交叉数据可能会有更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...
|...o...| 第一次备份
|.....o............| 第二次备份
|....o...o.............| 删除一部分数据后同时做第三次备份数据库
|.o..o..o..............| 又删除一部分数据,第四次备份
|....o......o.......o.........| 第五次备份,没有删除数据
|.......o.......o.........o............| 第六次备份,依然没有删除数据
|.o....o......o............| 删除很多数据,第七次备份
我用'o' 表示与上次备份中有差异的部分。
3. 恢复方案
,最好恢复,第二种。
上面所提三种备份方式
- 第一种
- 最好恢复,100% 都能搞定.
- 第二种
- 恢复起来稍复杂,仍能搞得定.
- 第三种
- 比较复杂,因为本档案中存在重复记录,费点脑筋
- 第四种
- 最复杂,看似复杂,其实也不复杂,跟第三种差不多.
3.1. 第一种
这种备份非常简单,菜鸟也搞搞定
文本格式回复
cat dbname.sql | mysql -u user -p pass -h localhost yourdb
压缩格式恢复
zcat dbname.sql.gz | mysql -u user -p pass -h localhost yourdb
或者先使用gunzip解压,再恢复数据
gunzip dbname.sql.gz
cat dbname.sql | mysql -u user -p pass -h localhost yourdb
提示
很多人喜欢用tar打包,我不见这样做,一个文件时无需使用tar打包的,画蛇添足
仅使用gzip压缩,可以方便使用zcat直接操作文件。
3.2. 第二种
这种备份是连续有规律的,只要依次按顺序恢复即可。
zcat dbname1.sql.gz | mysql -u user -p pass -h localhost yourdb
zcat dbname2.sql.gz | mysql -u user -p pass -h localhost yourdb
zcat dbname3.sql.gz | mysql -u user -p pass -h localhost yourdb
...
...
zcat dbname10.sql.gz | mysql -u user -p pass -h localhost yourdb
也可以跳跃恢复数据
zcat dbname2.sql.gz | mysql -u user -p pass -h localhost yourdb
zcat dbname3.sql.gz | mysql -u user -p pass -h localhost yourdb
zcat dbname5.sql.gz | mysql -u user -p pass -h localhost yourdb
zcat dbname10.sql.gz | mysql -u user -p pass -h localhost yourdb
反向恢复数据
zcat dbname20.sql.gz | mysql -u user -p pass -h localhost yourdb
zcat dbname15.sql.gz | mysql -u user -p pass -h localhost yourdb
zcat dbname13.sql.gz | mysql -u user -p pass -h localhost yourdb
zcat dbname1.sql.gz | mysql -u user -p pass -h localhost yourdb
总之怎么恢复都可以
3.3. 第三种
这种恢复建议按照顺序进行,因为重叠数据没有变化,所以即可以顺时间轴恢复也可以逆时间轴,条件是表结构需要有主键(PK)
insert 方式有要求
必须是
INSERT INTO dbtable(f1, f2, f3...) value (v1, v2, v3);
INSERT INTO dbtable(f1, f2, f3...) value (v1, v2, v3);
INSERT INTO dbtable(f1, f2, f3...) value (v1, v2, v3);
不能是
INSERT INTO dbtable(f1, f2, f3...) value (v1, v2, v3), (v1, v2, v3), value (v1, v2, v3);
这种备份参数如下
mysqldump -C -hlocalhost -ubackup -p1AyBoc5mp02LDJki5wJ8 --skip-extended-insert -t db_name tbl_name
这种方式备份,备份文件尺寸会比较大。
正时序恢复案例,
zcat dbname1.sql.gz | sed 's/^INSERT INTO/INSERT IGNORE INTO/' | mysql -u user -p pass -h localhost yourdb
zcat dbname2.sql.gz | sed 's/^INSERT INTO/INSERT IGNORE INTO/' | mysql -u user -p pass -h localhost yourdb
zcat dbname3.sql.gz | sed 's/^INSERT INTO/INSERT IGNORE INTO/' | mysql -u user -p pass -h localhost yourdb
逆时序恢复数据
zcat dbname3.sql.gz | sed 's/^INSERT INTO/INSERT IGNORE INTO/' | mysql -u user -p pass -h localhost yourdb
zcat dbname2.sql.gz | sed 's/^INSERT INTO/INSERT IGNORE INTO/' | mysql -u user -p pass -h localhost yourdb
zcat dbname1.sql.gz | sed 's/^INSERT INTO/INSERT IGNORE INTO/' | mysql -u user -p pass -h localhost yourdb
因为有主键,所以已存在的重复记录不会被重复插入。
3.4. 第四种
这种恢复必须按照顺序进行,即可以顺时间轴恢复也可以逆时间轴,但处理上稍有不同.一旦操作错误数据就会损坏,同时也有很多条件。
顺时序恢复数据, 只需将 insert 替换为 replace 即可
replace into dbtable(f1, f2, f3...) value (v1, v2, v3);
replace into dbtable(f1, f2, f3...) value (v1, v2, v3);
replace into dbtable(f1, f2, f3...) value (v1, v2, v3);
新数据总会覆盖旧数据
但逆向就不同了,逆时序恢复数据与上面第三种相同, 恢复过程中旧数据在 insert 的时候不会覆盖现有的新数据。仅仅将失去的数据恢复到数据库中。
操作要十分谨慎,理解正向与逆向的不同,方能操作。
4. 手工恢复
有时上面所讲的四种恢复方法不能满足你需求,我们模拟一个场景,假如你需要恢复一个时间段的数据,或者ID字段去一个范围等等,上面所举例子均为一刀切。该怎么办呢?
不用担心方法总是有的
INSERT ... SELECT
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
REPLACE ... SELECT
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
SELECT ...
例 1. INSERT ... SELECT
INSERT IGNORE INTO tbl_name_new SELECT * FROM tbl_name_old WHERE name = 'netkiller';
INSERT IGNORE INTO db_new.tbl_name SELECT * FROM db_old.tbl_name WHERE id > '10000';
IGNORE 将忽略 ERROR 1062 (23000) at line 24: Duplicate entry '100' for key 'PRIMARY'
这里仅给一个简单实例,因为每个人的需求都不同,你只需灵活变通,发挥你的想象力。
- CSS魔法堂:"那不是bug,是你不懂我!" by inline-block
- scala 学习笔记(03) 参数缺省值、不定个数参数、类的属性(Property)、泛型初步
- Cmd Markdown编辑器简明语法手册
- 如何让spring mvc web应用启动时就执行特定处理
- CSS魔法堂:小结一下Box Model与Positioning Scheme
- jboss EAP 6.2+ 通过代码控制JNDI数据源
- jboss CLI 命令行接口学习(适用JBOSS EAP 6.2+)
- WebComponent魔法堂:深究Custom Element 之 面向痛点编程
- 修复bootstrap daterangepicker中的3个问题
- 搭建AngualarJS开发环境
- CSS魔法堂:重拾Border之——更广阔的遐想
- Jboss EAP:native management API学习
- linux:手动校准系统时间和硬件CMOS时间
- CSS3魔法堂:说说Multi-column Layout
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 详解Go变量类型的内存布局
- linux vim 编辑器之多文件多窗口编辑
- 深入解析 Go 中 Slice 底层实现
- 2017年的golang、python、php、c++、c、java、Nodejs性能对比(golang python php c++ java Nodejs Performance)
- linux文件时间属性 查看和修改文件时间
- Linux硬连接和软连接详解
- Linux 压缩,解压缩,打包指令
- Linux下使用python脚本执行BCP导入导出操作
- 通用高效字符串匹配--Sunday算法
- Golang fmt Printf 格式化参数手册/详解/说明
- 正则表达式(RegEx)官方手册/权威指南【Python】
- 玩透二叉树(Binary-Tree)及前序(先序)、中序、后序【递归和非递归】遍历
- 如何写出优雅的 Golang 代码
- 检测代码潜在bug和质量之SonarQube
- 基于cephfs搭建高可用分布式存储并mount到本地