PostgreSQL 恢复误删数据的操作

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

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

1、有完整的基础数据文件备份和归档文件备份.所以备份是很重要的。

2、有一台装好同款Postgres软件的服务器

实例模拟讲解

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

1、创建一个有效的备份

Postgres201 : 线上数据库服务器
Postgres202 : 操作服务器
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多种恢复实例分析

Postgresql归档恢复实例分析(时间线机制)

这篇文章根据实例介绍Postgresql归档恢复的方法,时间线的含义。

1 参数配置

sed -ir "s/#*max_wal_senders.*/max_wal_senders = 10/" $PGDATA/postgresql.conf
sed -ir "s/#*wal_level.*/wal_level = replica/" $PGDATA/postgresql.conf
sed -ir "s/#*archive_mode.*/archive_mode = on/" $PGDATA/postgresql.conf
sed -ir "s/#*archive_command.*/archive_command = 'test ! -f \${PGHOME}\/archive\/%f \&\& cp %p \${PGHOME}\/archive\/%f'/" $PGDATA/postgresql.conf

2 数据操作

date;psql -c "create table test00 (id int primary key, info text)"
Sat Apr 1 10:09:55 CST 2017
date;psql -c "insert into test00 values(generate_series(1,50000), repeat(md5(random()::text), 1000))"
Sat Apr 1 10:10:10 CST 2017
date;psql -c "create table test01 (id int primary key, info text)"
Sat Apr 1 10:10:48 CST 2017
date;psql -c "insert into test01 values(generate_series(1,50000), repeat(md5(random()::text), 1000))"
Sat Apr 1 10:10:53 CST 2017

3 制作基础备份

sed -ir "s/#*max_wal_senders.*/max_wal_senders = 10/" $PGDATA/postgresql.conf

配置pg_hba.conf通道

pg_basebackup -Fp -P -x -D ~/bin/data/pg_root21 -l basebackup21

4 数据库上继续进行业务操作(模拟在基础备份后,业务继续下发,然后发生故障)

date;psql -c "create table test02 (id int primary key, info text)"
Sat Apr 1 10:15:59 CST 2017
date;psql -c "insert into test02 values(generate_series(1,100000), repeat(md5(random()::text), 1000))"
Sat Apr 1 10:16:09 CST 2017

时间轴(第三行的缩写代表Create Insert)

-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|-------------|-----------|------
C test00-----I test00-----C test01-----I test01-----C test01-----I test01--

情况1

没有设置archive_timeout,整个数据目录被删除

5 数据目录被rm -rf掉了(模拟误操作)

rm -rf pg_root20/

6 归档恢复

cp -r pg_root21 pg_root20

修改pg_hba.conf阻止用户连接

cp $PGHOME/share/recovery.conf.sample ./recovery.conf
sed -ir "s/#*restore_command.*/restore_command = 'cp \${PGHOME}\/archive\/%f %p'/" $PGDATA/recovery.conf

7 恢复结果

test02存在,但是其中的数据被认为是未提交事务,表为空(最后一个xlog文件的内容全部遗失了)。

情况2

设置archive_timeout,整个数据目录被删除,归档timeout为60s,在test02表数据灌入之后,xlog自动切换并归档

(sed -ir "s/#*archive_timeout.*/archive_timeout = 60/" $PGDATA/postgresql.conf)

5 数据目录被rm -rf掉了(模拟误操作)

rm -rf pg_root20/

6 归档恢复

cp -r pg_root21 pg_root20

修改pg_hba.conf阻止用户连接

cp $PGHOME/share/recovery.conf.sample ./recovery.conf
sed -ir "s/#*restore_command.*/restore_command = 'cp \${PGHOME}\/archive\/%f %p'/" $PGDATA/recovery.conf

7 恢复结果

test02存在,数据也存在(由于归档设置了超时切换,最后一个xlog会被归档)。

情况3(重要)

设置archive_timeout,根据估计时间点尝试多次恢复,不能确定想恢复到具体哪个时间点,归档timeout为60s

(sed -ir "s/#*archive_timeout.*/archive_timeout = 60/" $PGDATA/postgresql.conf)

5 数据目录被rm -rf掉了(模拟误操作)

rm -rf pg_root20/

6 归档恢复

cp -r pg_root21 pg_root20

修改pg_hba.conf阻止用户连接

cp $PGHOME/share/recovery.conf.sample ./recovery.conf
sed -ir "s/#*restore_command.*/restore_command = 'cp \${PGHOME}\/archive\/%f %p'/" $PGDATA/recovery.conf

(1) recovery_target_time = ‘2017-4-1 10:09:47' (基础备份时间之前)

这里------------------------------------------------------------------------
-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|---basebackup---|--------|------
C test00-----I test00-----C test01-----I test01-----C test02-----I test02--

结果:

恢复时间定到了基础备份之前,所以这里会恢复到最早时间点:基础备份点。

LOG: recovery stopping before commit of transaction 1175, time 2017-04-01 10:15:59.597495+08

注意:无法恢复到基础备份之前的点,所以再做基础备份时,请保证数据一致性。

(2) recovery_target_time = ‘2017-4-1 10:10:00' (基础备份时间之前)

---------这里---------------------------------------------------------------
-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|---basebackup---|--------|------
C test00-----I test00-----C test01-----I test01-----C test02-----I test02--

结果:

恢复时间定到了基础备份之前,所以这里会恢复到最早时间点:基础备份点。

LOG: recovery stopping before commit of transaction 1175, time 2017-04-01 10:15:59.597495+08

注意:无法恢复到基础备份之前的点,所以再做基础备份时,请保证数据一致性。

(3) recovery_target_time = ‘2017-4-1 10:16:00'

-------------------------------------------------------------这里-----------
-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|---basebackup---|--------|------
C test00-----I test00-----C test01-----I test01-----C test02-----I test02--

结果:

表test02存在,但没有数据。说明如果时间在基础备份点之后,可以恢复到任意时间点。恢复后会创建新时间线。

LOG: last completed transaction was at log time 2017-04-01 10:15:59.597495+08

(3.1) 在(3)的基础上继续进行恢复:recovery_target_time = ‘2017-4-1 10:17:00'

------------------------------------------------------------------------这里
-10:09:55----10:10:10-----10:10:48-----10:10:53------10:15:59----10:16:09--
----|-----------|------------|------------|---basebackup---|--------|------
C test00-----I test00-----C test01-----I test01-----C test02-----I test02--

结果:

同3,这次恢复创建了一条新的时间线3,这条时间线上面进行恢复的话,数据库会去archive里面去找时间线2的xlog,但是归档目录中的日志应该都是时间线1的,所以会报错找不到xlog。

cp: cannot stat pathto/archive/00000002000000000000000A': No such file or directory

注意: 根据上述结论,请在每次恢复时都使用原始归档文件,即如果尝试再次恢复,请重新使用基础备份进行恢复,不要在前一次恢复的基础上继续进行,否则由于时间线切换,会找不到归档文件。

其他

压缩的归档日志

sed -ir "s/#*archive_command.*/archive_command = 'gzip -c %p > \${PGHOME}\/archive\/%f.gz'/" $PGDATA/postgresql.conf
sed -ir "s/#*restore_command.*/restore_command = 'gzip -d -c \${PGHOME}\/archive\/%f.gz > %p'/" $PGDATA/recovery.conf

1、recovery.conf(几个重要参数)

Postgresql9.6手册(彭煜玮翻译)

restore_command (string)

用于获取 WAL 文件系列的一个已归档段的本地 shell 命令。这个参数是归档恢复所必需的,但是对于流复制是可选的。在该字符串中的任何%f会被替换为从归档中获得的文件的名字,并且任何%p会被在服务器上的复制目标路径名替换(该路径名是相对于当前工作目录的,即集簇的数据目录)。任何%r会被包含上一个可用重启点的文件的名字所替换。在那些必须被保留用于使得一次恢复变成可重启的文件中,这个文件是其中最早的一个,因此这个信息可以被用来把归档截断为支持从当前恢复重启所需的最小值。%r通常只被温备配置(见Section 26.2)所使用。要嵌入一个真正的%字符,需要写成%%。很重要的一点是,该命令只有在成功时才返回一个为零的退出状态。该命令将会被询问不存在于归档中的文件名,当这样被询问时它必须返回非零。

recovery_target_time (timestamp)

这个参数指定恢复将进入的时间戳。

recovery_target_xid (string)

这个参数指定恢复将进入的事务 ID。记住虽然事务 ID 是在事务开始时顺序分配的,但是事务可能以不同的数字顺序完成。那些在指定事务之前(也可以包括该事务)提交的事务将被恢复。精确的停止点也受到recovery_target_inclusive的影响。

recovery_target_timeline (string)

指定恢复到一个特定的时间线中。默认值是沿着基础备份建立时的当前时间线恢复。将这个参数设置为latest会恢复到该归档中能找到的最新的时间线,这在一个后备服务器中有用。除此之外,你只需要在复杂的重恢复情况下设置这个参数,在这种情况下你需要返回到一个状态,该状态本身是在一次时间点恢复之后到达的。相关讨论见Section25.3.5

2、关于时间线

Postgresql9.6手册(彭煜玮翻译)

将数据库恢复到一个之前的时间点的能力带来了一些复杂性,这和有关时间旅行和平行宇宙的科幻小说有些相似。例如,在数据库的最初历史中,假设你在周二晚上5:15时丢弃了一个关键表,但是一直到周三中午才意识到你的错误。不用苦恼,你取出你的备份,恢复到周二晚上5:14的时间点,并上线运行。在数据库宇宙的这个历史中,你从没有丢弃该表。但是假设你后来意识到这并非一个好主意,并且想回到最初历史中周三早上的某个时间。你没法这样做,在你的数据库在线运行期间,它重写了某些WAL段文件,而这些文件本来可以将你引向你希望回到的时间。因此,为了避免出现这种状况,你需要将完成时间点恢复后生成的WAL记录序列与初始数据库历史中产生的WAL记录序列区分开来。

要解决这个问题,PostgreSQL有一个时间线概念。无论何时当一次归档恢复完成,一个新的时间线被创建来标识恢复之后生成的WAL记录序列。时间线ID号是WAL段文件名的一部分,因此一个新的时间线不会重写由之前的时间线生成的WAL数据。实际上可以归档很多不同的时间线。虽然这可能看起来是一个无用的特性,但是它常常扮演救命稻草的角色。考虑到你不太确定需要恢复到哪个时间点的情况,你可能不得不做多次时间点恢复尝试和错误,直到最终找到从旧历史中分支出去的最佳位置。如果没有时间线,该处理将会很快生成一堆不可管理的混乱。而有了时间线,你可以恢复到任何之前的状态,包括早先被你放弃的时间线分支中的状态。

每次当一个新的时间线被创建,PostgreSQL会创建一个“时间线历史”文件,它显示了新时间线是什么时候从哪个时间线分支出来的。系统在从一个包含多个时间线的归档中恢复时,这些历史文件对于允许系统选取正确的WAL段文件非常必要。因此,和WAL段文件相似,它们也要被归档到WAL归档区域。历史文件是很小的文本文件,因此将它们无限期地保存起来的代价很小,而且也是很合适的(而段文件都很大)。如果你喜欢,你可以在一个历史文件中增加注释来记录如何和为什么要创建该时间线。当你由于试验的结果拥有了一大堆错综复杂的不同时间线时,这种注释将会特别有价值。

恢复的默认行为是沿着相同的时间线进行恢复,该时间线是基础备份创建时的当前时间线。如果你希望恢复到某个子女时间线(即,你希望回到在一次恢复尝试后产生的某个状态),你需要在recovery.conf中指定目标时间线ID。你不能恢复到早于该基础备份之前分支出去的时间线。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 利用python为PostgreSQL的表自动添加分区

    PostgreSQL引进"分区"表特性,解放了之前采用"表继承"+"触发器"来实现分区表的繁琐.低效.而添加分区,都是手动执行SQL. 演示目的:利用python来为PostgreSQL的表自动添加分区. python版本:python3+ pip3 install psycopg2 一.配置数据源 database.ini 文件:记录数据库连接参数 [adsas] host=192.168.1.201 database=adsas user=a

  • PostgreSQL 打印日志信息所在的源文件和行数的实例

    一直好奇在PG中, 当输出错误日志时, 如何能够附带错误信息所在的源代码文件名以及发生错误的代码行数. postgres.conf中, log信息冗余级别为"default(默认)", terse: 表示更加简单的日志信息, verbose: 表示更加冗余的日志信息(即: 附带"文件名和行数) #log_error_verbosity = default # terse, default, or verbose messages 修改为下面的"verbose&quo

  • 基于Postgresql 事务的提交与回滚解析

    用过oracle或mysql的人都知道在sqlplus或mysql中,做一个dml语句,如果发现做错了,还可以rollback;掉,但在PostgreSQL的psql中,如果执行一个dml,没有先运行begin;的话,一执行完就马上提交了,不能回滚,这样容易导致误操作的发生,有没有什么办法避免这个风险呢? 当然有,在psql中默认是打开自动提交的,我们可以关闭自动提交,方法如下: 设置\set AUTOCOMMIT off test=# create table test1 (x int); C

  • PostgreSQL 实现给查询列表增加序号操作

    利用 ROW_NUMBER() over( ) 给查询序列增加排序字段 SELECT ROW_NUMBER() over(ORDER bY biztypename DESC ) AS num,biztypename FROM (SELECT DISTINCT biztypename FROM bizmaptype) t; 效果如下: 补充:PostgreSql 使用自定义序列(Sequence)向表插入数据 id 自增长 按照以往Oracle建表的流程,我们来新建表,并且向表中导入数据. 1.创

  • PostgreSQL 使用raise函数打印字符串

    raise函数 在PostgreSQL中,该函数用于打印字符串,类似于Java中的System.out.println(),Oracle中的dbms_output.put_line(). 用法如下: raise notice 'My name is %, I am a %.', 'Lewis', 'coder'; 以上sql会在控制台输出My name is Lewis, I am a coder..如果是在DBeaver里使用该函数,则会在output的tab里输出字符串. raise后面的n

  • postgresql 如何关闭自动提交

    postgresql中默认是自动提交的 查看是否是自动提交: postgres=# \echo :AUTOCOMMIT on 关闭自动提交: postgres=# \set AUTOCOMMIT off postgres=# \echo :AUTOCOMMIT off 另一种方式就在会话开始的时候以begin开始相当于关闭了自动提交,以end或者commit结束就可以了 补充:pg(hgdb)默认事务自动提交 默认情况下,AUTOCOMMIT(自动提交)是开着的,也就是说任何一个SQL语句执行完

  • PostgreSQL 日志文件的所在位置

    1.查看postgresql.conf文件的配置,看日志文件在哪 logging_collector = on log_directory = 'pg_log' log_filename = 'postgresql-%a.log' log_truncate_on_rotation = o 2.日志的分类 pg_log(数据库运行日志) 内容可读 默认关闭的,需要设置参数启动 pg_xlog(WAL 日志,即重做日志) 内容一般不具有可读性 强制开启 pg_clog(事务提交日志,记录的是事务的元

  • Postgresql 解决pg掉电后无法重启的问题

    机房断电后重启pg数据库,报如下错误: < 2019-01-01 22:42:59.240 EST >LOG: database system was interrupted while in recovery at 2019-01-01 22:00:58 EST < 2019-01-01 22:42:59.240 EST >HINT: This probably means that some data is corrupted and you will have to use

  • PostgreSQL 恢复误删数据的操作

    在Oracle中:删除表或者误删表记录:有个闪回特性,不需要停机操作,可以完美找回记录.当然也有一些其他的恢复工具:例如odu工具,gdul工具.都可以找回数据.而PostgreSQL目前没有闪回特性.如何在不停机情况下恢复误删数据.还好是有完整的热备份. 本文描述的方法是:利用热备份在另一台服务器进行数据恢复:再导入正式环境:这样不影响数据库操作.这方法也适用在Oracle恢复.必须满足几个条件 1.有完整的基础数据文件备份和归档文件备份.所以备份是很重要的. 2.有一台装好同款Postgre

  • delete误删数据使用SCN号恢复(推荐)

    问题描述:使用scn号恢复误删数据 1.查询系统闪回的scn值以及当前日志的scn值,因为我这个是测试,创建的表是在在后边,所以scn值要大于下边这两个scn值,所以对我恢复数据没有用,如果我创建的数据是在下边这两个SCN值之前,也就是比这两个时间点SCN值小,就可以用这两个scn用来恢复数据,但是我下边这个实验创建的测试表晚,就不行了 SQL> select dbms_flashback.get_system_change_number from dual; SQL> select curr

  • 恢复sql server 2000误删数据的解决办法

    今天不小心把客户那边的数据库中删了一千多条数据,而且之前又没有备份,真的是很郁闷,后来在网上找到一工具,用起来挺方便,让我躲过一劫. 首先来看一下界面: 输入服务器地址,用户名及密码后点Connect,进入到下面的界面: 在这里选择要恢复数据的数据库,选择Use On-line Log(如果你又备份文件的话就不需要用这个工具了,直接用SQL搞定了).然后点Attach,进入下面的界面: 可以看到左边菜单中有很多功能,我们要恢复数据,首先要查看日志,找出我们误操作的那些日志记录,点Browse下的

  • 详解如何通过Mysql的二进制日志恢复数据库数据

    经常有网站管理员因为各种原因和操作,导致网站数据误删,而且又没有做网站备份,结果不知所措,甚至给网站运营和盈利带来负面影响.所以本文我们将和大家一起分享学习下如何通过Mysql的二机制日志(binlog)来恢复数据. 系统环境: 操作系统:CentOS 6.5 X64  (虚拟机): WEB服务:PHP+Mysql+apache: 网站:为方便,直接在本地用蝉知系统搭建一个DEMO站点: 操作步骤: 1.开启binlog功能及基本操作: 2.往站点添加数据: 3.刷新binlog日志: 4.删除

  • Mysql误删数据解决方案及kill语句原理

    mysql误删数据 使用delete语句误删数据行 使用drop table或者truncate table误删数据表 使用drop database语句误删数据库 使用rm误删mysql整个实例 对于误删行 使用flashback工具闪回,把数据恢复回来.原理是修改binlog的内容,拿回原库重放,需要确保binlog_format=row和binlog_row_imsge=Full 具体恢复时 如果是insert,将binlog event类型是write_rows event改为delet

  • 如何利用MySQL的binlog恢复误删数据库详解

    目录 1 查看当前数据库内容并备份数据库 2 开启bin_log功能 3 模拟误操作(插入3条数据,删除数据库) 4 数据恢复 5 总结 1 查看当前数据库内容并备份数据库 查看数据库信息: 备份数据库: [root@localhost ~]# mysqldump -u root -p t > /mnt/t.sql Enter password: [root@localhost ~]# ll /mnt/t.sql -rw-r--r-- 1 root root 1771 Aug 25 11:56

  • PHP实现从PostgreSQL数据库检索数据分页显示及根据条件查找数据示例

    本文实例讲述了PHP实现从PostgreSQL数据库检索数据分页显示及根据条件查找数据.分享给大家供大家参考,具体如下: 主要功能是从postgreSql查询数据,并检索,由于自己刚开始接触,所以难点在于多条数据同时筛选并分页显示出来,写下自己的代码与大家共享. <html> <head> <script type="text/javascript"> /** * 分页函数 * pno--页数 * psize--每页显示记录数 * 分页部分是从真实数

  • jupyter notebook 恢复误删单元格或者历史代码的实现

    1.先说恢复误删单元格的操作 场景:不小心把某个cell给cut了,或者删除了单元格(前提不要关闭notebook窗口). 解决方法: 先按Esc键进入命令模式,在按z键就会恢复.记住不要按Ctrl+z(这个只限没删除单元格的常规操作) 命令模式和编辑模式识别: 命令模式:左侧为蓝色. 编辑模式:左侧为绿色,可以直接写入内容. 2.恢复原来写过的代码 场景:在某个窗口写了很多代码,又删除了很多单元格,想找回原来的代码. 解决方法: 直接在一个单元格中输入:history (如图) 就会展示出历史

  • 详解PostgreSQL提升批量数据导入性能的n种方法

    关键字:批量数据导入,数据加载,大量插入,加快,提升速度 多元化选择时代,人生里很多事物都是如此,凡事都没有一成不变的方式和方法.不管白猫黑猫,能抓老鼠的就是好猫,适合自己的就是最好的. 提升批量数据导入的方法亦是如此,没有何种方法是最优的,应用任何方法前根据自己的实际情况权衡利弊,做出选择. 批量导入数据之前,无论采取何种方式,务必做好相应的备份. 导入完成后亦需对相应对象进行ANALYZE操作,这样查询优化器才会按照最新的统计信息生成正确的执行计划. 下面正式介绍提升批量数据导入性能的n种方

  • mysql利用mysqlbinlog命令恢复误删除数据的实现

    实验环境: MYSQL 5.7.22 开启二进志日志 日志格式MIXED 实验过程: 1.执行:FLUSH LOGS; master-bin.000014 文件就是新生成的文件 刷新日志是为了实验内容更直观,更容易观察到整个实验过程的内容. 我看到网上许多文章有在用REST MASTER;而未说明此命令的严重性 这条命令会删除所有日志文件,并将文件名和记录点进行重置归零,99%的情况下是用不到这条命令的 删除日志可以用PURGE MASTER LOGS...这样保险一点 2.新日志文件已经生成,

随机推荐