在Oracle中;删除表或者误删表记录;有个闪回特性,不需要停机操作,可以完美找回记录。当然也有一些其他的恢复工具;例如odu工具,gdul工具。都可以找回数据。而PostgreSQL目前没有闪回特性。如何在不停机情况下恢复误删数据。还好是有完整的热备份。

  本文描述的方法是:利用热备份在另一台服务器进行数据恢复;再导入正式环境;这样不影响数据库操作。这方法也适用在Oracle恢复。必须满足几个条件

  1. 有完整的基础数据文件备份和归档文件备份.所以备份是很重要的。
  2. 有一台装好同款Postgres软件的服务器

实例模拟讲解

  过程模拟误删表tbl_lottu_drop后;后续进行dml/ddl操作;表明正式数据库还是进行正常工作。在另外一台数据库基于数据库PITR恢复。恢复表tbl_lottu_drop的数据。

  • Postgres201 : 线上数据库服务器
  • Postgres202 : 操作服务器

1. 创建一个有效的备份

postgres=# select pg_start_backup(now()::text);
pg_start_backup
-----------------
0/F000060
(1 row) [postgres@Postgres201 ~]$ rsync -acvz -L --exclude "pg_xlog" --exclude "pg_log" $PGDATA /data/backup/20180428 postgres=# select pg_stop_backup();
NOTICE: pg_stop_backup complete, all required WAL segments have been archived
pg_stop_backup
----------------
0/F000168
(1 row)

2. 模拟误操作

  2.1 创建一个需要恢复对象表tbl_lottu_drop。并插入1000记录。也保证数据从数据缓存写入磁盘中。

lottu=> create table tbl_lottu_drop (id int);
CREATE TABLE
lottu=> insert into tbl_lottu_drop select generate_series(1,1000);
INSERT 0 1000
lottu=> \c lottu postgres
You are now connected to database "lottu" as user "postgres".

  2.2 这个获取一个时间:用于后面基于数据库PITR恢复(当然现实操作后只能记住一个大概的时间;还往往是不准;可能记住的时间是误操作之后。后面有讲解如何获取需要恢复到那个时间点)

lottu=# select now();
now
-------------------------------
2018-04-28 20:47:31.617808+08
(1 row)
lottu=# checkpoint;
CHECKPOINT
lottu=# select pg_xlogfile_name(pg_switch_xlog());
pg_xlogfile_name
--------------------------
000000030000000000000010
(1 row)

  2.3 进行drop表

lottu=# drop table tbl_lottu_drop;
DROP TABLE

  2.4 后续进行dml/ddl操作;表明正式数据库还是进行正常工作

lottu=# create table tbl_lottu_log (id int);
CREATE TABLE
lottu=# insert into tbl_lottu_log values (1),(2);
INSERT 0 2
lottu=# checkpoint;
CHECKPOINT
lottu=# select pg_xlogfile_name(pg_switch_xlog());
pg_xlogfile_name
--------------------------
000000030000000000000011
(1 row)

3. 恢复操作

  3.1 将备份拷贝到Postgres202数据库上

[postgres@Postgres201 20180428]$ cd /data/backup/20180428
[postgres@Postgres201 20180428]$ ll
total 4
drwx------. 18 postgres postgres 4096 Apr 28 20:42 data
[postgres@Postgres201 20180428]$ rsync -acvz -L data postgres@192.168.1.202:/data/postgres

  3.2 删除不必要的文件

[postgres@Postgres202 data]$ cd $PGDATA
[postgres@Postgres202 data]$ rm backup_label.old postmaster.pid tablespace_map.old

  3.3 还原备份表空间软链接

[postgres@Postgres202 data]$ cat tablespace_map
16385 /data/pg_data/lottu
[postgres@Postgres202 data]$ mkdir -p /data/pg_data
[postgres@Postgres202 data]$ cd pg_tblspc/
[postgres@Postgres202 pg_tblspc]$ mv 16385/ /data/pg_data/lottu
[postgres@Postgres202 pg_tblspc]$ ln -s /data/pg_data/lottu ./16385
[postgres@Postgres202 pg_tblspc]$ ll
total 0
lrwxrwxrwx. 1 postgres postgres 19 Apr 28 23:12 16385 -> /data/pg_data/lottu

  3.4 将wal日志拷贝到Postgres202数据库上pg_xlog目录下;从哪个日志开始拷贝?

[postgres@Postgres202 data]$ mkdir -p pg_xlog/archive_status
[postgres@Postgres202 data]$ cat backup_label
START WAL LOCATION: 0/F000060 (file 00000003000000000000000F)
CHECKPOINT LOCATION: 0/F000098
BACKUP METHOD: pg_start_backup
BACKUP FROM: master
START TIME: 2018-04-28 20:42:15 CST
LABEL: 2018-04-28 20:42:13.244358+08

  查看backup_label;知道00000003000000000000000F开始到正在写入的wal日志。

[postgres@Postgres202 pg_xlog]$ ll
total 65540
-rw-------. 1 postgres postgres 16777216 Apr 28 20:42 00000003000000000000000F
-rw-------. 1 postgres postgres 313 Apr 28 20:42 00000003000000000000000F.00000060.backup
-rw-------. 1 postgres postgres 16777216 Apr 28 20:48 000000030000000000000010
-rw-------. 1 postgres postgres 16777216 Apr 28 20:50 000000030000000000000011
-rw-------. 1 postgres postgres 16777216 Apr 28 20:55 000000030000000000000012

  3.5 编辑recovery.conf文件

[postgres@Postgres202 data]$ vi recovery.conf 

restore_command = 'cp /data/arch/%f %p'            # e.g. 'cp /mnt/server/archivedir/%f %p'
recovery_target_time = '2018-04-28 20:47:31.617808+08'
recovery_target_inclusive = false
recovery_target_timeline = 'latest'

  3.6 启动数据库;并验证数据

[postgres@Postgres202 data]$ pg_start
server starting
[postgres@Postgres202 data]$ ps -ef | grep postgres
root 1098 1083 0 22:32 pts/0 00:00:00 su - postgres
postgres 1099 1098 0 22:32 pts/0 00:00:00 -bash
root 1210 1195 0 22:55 pts/1 00:00:00 su - postgres
postgres 1211 1210 0 22:55 pts/1 00:00:00 -bash
postgres 1442 1 1 23:16 pts/0 00:00:00 /opt/pgsql96/bin/postgres
postgres 1450 1442 0 23:16 ? 00:00:00 postgres: checkpointer process
postgres 1451 1442 0 23:16 ? 00:00:00 postgres: writer process
postgres 1459 1442 0 23:16 ? 00:00:00 postgres: wal writer process
postgres 1460 1442 0 23:16 ? 00:00:00 postgres: autovacuum launcher process
postgres 1461 1442 0 23:16 ? 00:00:00 postgres: archiver process last was 00000005.history
postgres 1462 1442 0 23:16 ? 00:00:00 postgres: stats collector process
postgres 1464 1099 0 23:16 pts/0 00:00:00 ps -ef
postgres 1465 1099 0 23:16 pts/0 00:00:00 grep postgres
[postgres@Postgres202 data]$ psql
psql (9.6.0)
Type "help" for help. postgres=# \c lottu lottu
You are now connected to database "lottu" as user "lottu".
lottu=> \dt
List of relations
Schema | Name | Type | Owner
--------+----------------+-------+-------
public | pitr_test | table | lottu
public | tbl_lottu_drop | table | lottu lottu=> select count(1) from tbl_lottu_drop;
count
-------
1000
(1 row)

  从这看数据是恢复了;copy到线上数据库操作略。

延伸点

下面讲解下如何找到误操作的时间。即recovery_target_time = '2018-04-28 20:47:31.617808+08'的时间点。上文是前面已经获取的;

  1. 用pg_xlogdump解析这段日志。

[postgres@Postgres201 pg_xlog]$ pg_xlogdump -b 00000003000000000000000F 000000030000000000000012 > lottu.log
pg_xlogdump: FATAL: error in WAL record at 0/12000648: invalid record length at 0/12000680: wanted 24, got 0

  2. 从lottu.log中可以找到这段日志

rmgr: Transaction len (rec/tot):      8/    34, tx:       1689, lsn: 0/100244A0, prev 0/10024460, desc: COMMIT 2018-04-28 20:45:49.736013 CST
rmgr: Standby len (rec/tot): 24/ 50, tx: 0, lsn: 0/100244C8, prev 0/100244A0, desc: RUNNING_XACTS nextXid 1690 latestCompletedXid 1689 oldestRunningXid 1690
rmgr: Heap len (rec/tot): 3/ 3130, tx: 1690, lsn: 0/10024500, prev 0/100244C8, desc: INSERT off 9
blkref #0: rel 16385/16386/2619 fork main blk 15 (FPW); hole: offset: 60, length: 5116 rmgr: Btree len (rec/tot): 2/ 7793, tx: 1690, lsn: 0/10025140, prev 0/10024500, desc: INSERT_LEAF off 385
blkref #0: rel 16385/16386/2696 fork main blk 1 (FPW); hole: offset: 1564, length: 452 rmgr: Heap len (rec/tot): 2/ 184, tx: 1690, lsn: 0/10026FD0, prev 0/10025140, desc: INPLACE off 16
blkref #0: rel 16385/16386/1259 fork main blk 0
rmgr: Transaction len (rec/tot): 88/ 114, tx: 1690, lsn: 0/10027088, prev 0/10026FD0, desc: COMMIT 2018-04-28 20:46:37.718442 CST; inval msgs: catcache 49 catcache 45 catcache 44 relcache 32784
rmgr: Standby len (rec/tot): 24/ 50, tx: 0, lsn: 0/10027100, prev 0/10027088, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: Standby len (rec/tot): 24/ 50, tx: 0, lsn: 0/10027138, prev 0/10027100, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: XLOG len (rec/tot): 80/ 106, tx: 0, lsn: 0/10027170, prev 0/10027138, desc: CHECKPOINT_ONLINE redo 0/10027138; tli 3; prev tli 3; fpw true; xid 0:1691; oid 40976; multi 1; offset 0; oldest xid 1668 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 1691; online
rmgr: Standby len (rec/tot): 24/ 50, tx: 0, lsn: 0/100271E0, prev 0/10027170, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: Standby len (rec/tot): 24/ 50, tx: 0, lsn: 0/10027218, prev 0/100271E0, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: XLOG len (rec/tot): 80/ 106, tx: 0, lsn: 0/10027250, prev 0/10027218, desc: CHECKPOINT_ONLINE redo 0/10027218; tli 3; prev tli 3; fpw true; xid 0:1691; oid 40976; multi 1; offset 0; oldest xid 1668 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 1691; online
rmgr: XLOG len (rec/tot): 0/ 24, tx: 0, lsn: 0/100272C0, prev 0/10027250, desc: SWITCH
rmgr: Standby len (rec/tot): 24/ 50, tx: 0, lsn: 0/11000028, prev 0/100272C0, desc: RUNNING_XACTS nextXid 1691 latestCompletedXid 1690 oldestRunningXid 1691
rmgr: Standby len (rec/tot): 16/ 42, tx: 1691, lsn: 0/11000060, prev 0/11000028, desc: LOCK xid 1691 db 16386 rel 32784
rmgr: Heap len (rec/tot): 8/ 2963, tx: 1691, lsn: 0/11000090, prev 0/11000060, desc: DELETE off 16 KEYS_UPDATED
blkref #0: rel 16385/16386/1247 fork main blk 8 (FPW); hole: offset: 88, length: 5288

根据“32784”日志可以看到是表tbl_lottu_drop在2018-04-28 20:46:37.718442插入1000条记录(所以恢复时间点选2018-04-28 20:47:31.617808+08没毛病);即也是在事务id为1690操作的。并在事务id为1691进行删除操作。

所以上面的recovery.conf 也可以改写为:

restore_command = 'cp /data/arch/%f %p'            # e.g. 'cp /mnt/server/archivedir/%f %p'
recovery_target_xid = '1690'
recovery_target_inclusive = false
recovery_target_timeline = 'latest'

PostgreSQL恢复误删数据的更多相关文章

  1. Mongodb全备+增备+oplog恢复误删数据

    此时测试表中有7条数据,做个全备. 全备: mongodump --host=192.168.43.43 --port=37017 --oplog --out=/opt/mongo/fullbacku ...

  2. Oracle恢复误删数据

    1.先查出被删除的时间点: select * from flashback_transaction_query where table_name='表名'; 2.根据时间点恢复数据: insert i ...

  3. mysqlbinlog恢复误删数据

    概述 代码bug,在处理上传出现异常时执行了DELETE FROM t_resource WHERE resource_id = ? OR parent_id = ?因为OR条件导致用户的上传的所有数 ...

  4. oracle 恢复误删数据

    快照  select * from sys_info as of timestamp to_Date('2014-04-08 15:28:00', 'yyyy-mm-dd hh24:mi:ss')   ...

  5. delete误删数据使用SCN恢复

    参考51CTO博客 问题描述:使用scn号恢复误删数据 1.查询系统闪回的scn值以及当前日志的scn值,因为我这个是测试,创建的表是在在后边,所以scn值要大于下边这两个scn值,所以对我恢复数据没 ...

  6. Oracle- 查询误删数据

    使用flashback table能恢复误删数据. flashback table CONTAINER_CONTENT to timestamp to_timestamp('2010-06-30 22 ...

  7. 恢复HDFS误删数据

    [恢复HDFS误删数据] HDFS会为每一个用户创建一个回收站目录:/user/用户名/.Trash/,每一个被用户通过Shell删除的文件/目录,在系统回收站中都一个周期,也就是当系统回收站中的文件 ...

  8. CentOS 恢复 rm -rf * 误删数据(转)

    一. 将磁盘分区挂载为只读 这一步很重要,并且在误删除文件后应尽快将磁盘挂载为只读.越早进行,恢复的成功机率就越大. 1.  查看被删除文件位于哪个分区 [root@localhost  ~]# mo ...

  9. 使用git恢复未提交的误删数据

    不小心将项目中一个文件夹删除还未提交,或者已经提交, 此时想要恢复数据该怎么办? 答案是git reflog,使用git reflog命令可以帮助恢复git误操作,进行数据恢复. 操作过程: 打开终端 ...

随机推荐

  1. Java设计模式(9)适配器模式(Adapter模式)

    适配器模式定义:将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和Adaptor(适配器)两个身份. 为何使用适配器模式 我们经常碰到要将两个没有关系的类组合在一起使用 ...

  2. SparkR(R on Spark)编程指南 含 dataframe操作 2.0

    SparkR(R on Spark)编程指南 Spark  2015-06-09 28155  1评论 下载为PDF    为什么不允许复制 关注iteblog_hadoop公众号,并在这里评论区留言 ...

  3. 安卓程序代写 网上程序代写[转]SVN 在线代码托管工具

    本文转载自 : http://blog.csdn.net/ithomer/article/details/8142920  作者:阳光岛主 在互联网环境使用SVN服务,你必须要有一台在互联网环境内支持 ...

  4. 关于Unity中协程、多线程、线程锁、www网络类的使用

    协程 我们要下载一张图片,加载一个资源,这个时候一定不是一下子就加载好的,或者说我们不一定要等它下载好了才进行其他操作,如果那样的话我就就卡在了下载图片那个地方,傻住了.我们希望我们只要一启动加载的命 ...

  5. 【转】【Centos】Centos下用upstart管理自己的服务程序

    Upstart是Ubuntu用来进行服务进程管理的服务,本文介绍如何利用upstart来通过Centos操作系统管理我们自己开发的应用程序. 什么时候要管理我们的应用程序?当我们开发出服务类的应用程序 ...

  6. imx6 lvds0 lvds1 display

    最近调试imx6的屏幕显示,笔记记录于此. 官方文档关于uboot参数的介绍: sin和dul参数已经测试过,sep和spl还没有验证成功. 1 单屏显示 说明:输入命令并按确定键, 观察系统启动过程 ...

  7. GitHub developer API 学习

    官网地址:https://developer.github.com/v3/ 目录 当前版本 schema parameters root endpoint client errors http red ...

  8. 第三百九十节,Django+Xadmin打造上线标准的在线教育平台—Django+cropper插件头像裁剪上传

    第三百九十节,Django+Xadmin打造上线标准的在线教育平台—Django+cropper插件头像裁剪上传 实现原理 前台用cropper插件,将用户上传头像时裁剪图片的坐标和图片,传到逻辑处理 ...

  9. 【转载】C#之玩转反射

    前言 之所以要写这篇关于C#反射的随笔,起因有两个:   第一个是自己开发的网站需要用到   其次就是没看到这方面比较好的文章. 所以下定决心自己写一篇,废话不多说开始进入正题. 前期准备 在VS20 ...

  10. unity-------------------打包BuildAssetBundles的使用

    unity5打包机制下,一种资源打ab和资源管理的方案.1.打ab: 1.设置平台 2.清楚所有资源的assetbundlename: string[] abNameArr = AssetDataba ...