这种情况下需要闪回来救命,回到被破坏前的状态。

DML闪回和DDL闪回。

DML闪回指对INSET, UPDATE, DELETE操作的闪回。DDL闪回指DROP, TRUNCATE操作的闪回。

闪回的实现分两种:

1、物理回退,相当于使用物理备份和归档进行时间点恢复,全库恢复到误操作前的状态。

(可以新建一个库用于恢复,恢复到目标时间点,恢复后,将误操作前的数据导出来,再导入线上数据库。)

2、在当前库回退,在当前库,将误操作影响的数据找出来。

闪回的手段:

1、物理回退,PG内核已支持时间点恢复,只要有误操作前的全量备份和所有归档即可。

2、当前库回退,使用HOOK,可以实现DROP和TRUNCATE操作的回收站功能。

3、使用延迟垃圾回收、脏读、行头事务号、事务提交日志,可以实现DML操作的闪回。

以前写的一些闪回方案:

《PostgreSQL 闪回 - flash back query emulate by trigger》

《PostgreSQL 回收站功能 - 基于HOOK的recycle bin pgtrashcan》

《PostgreSQL 最佳实践 - 在线增量备份与任意时间点恢复》

《PostgreSQL PITR THREE recovery target MODE: name,xid,time USE CASE - 2》

本文将详细介绍“使用延迟垃圾回收、脏读、行头事务号、事务提交日志,实现DML操作的闪回。”的方法。

flashback 前提

1、延迟VACUUM,确保误操作的数据还没有被垃圾回收。

2、记录未被freeze,确保无操作的数据,以及后面提交的事务号没有被freeze(抹去)。

3、开启事务提交时间跟踪,确保可以从xid得到事务结束的时间。(开启事务结束时间跟踪后,会开辟一块共享内存区存储这个信息。)。

  1. track_commit_timestamp = on # 开启事务结束时间跟踪
  1. Size
  2. CommitTsShmemBuffers(void)
  3. {
  4. return Min(16, Max(4, NBuffers / 1024));
  5. }
  1. cd $PGDATA
  2. ll
  3. drwx------ 2 digoal users 4.0K Oct 10 10:28 pg_commit_ts

flashback 准备工作

1、将xid转换为txid的函数,见本文末尾。(因为记录的行头部,存储的是XID,而不是TXID,而查询事务提交状态,用的是TXID,因此需要转换一下。)

2、脏读插件pg_dirtyread(用于读取脏页)

https://github.com/ChristophBerg/pg_dirtyread

  1. create extension pg_dirtyread ;

3、根据txid查询事务提交状态

  1. postgres=# select txid_status(2);
  2. txid_status
  3. -------------
  4. committed
  5. (1 row)

4、根据xid查询事务提交时间

  1. postgres=# select xmin,xmax,xid_to_txid(xmin),txid_status(xid_to_txid(xmin)),pg_xact_commit_timestamp(xmin) from trac ;
  2. xmin | xmax | xid_to_txid | txid_status | pg_xact_commit_timestamp
  3. ----------+----------+-------------+-------------+-------------------------------
  4. 40477717 | 40477727 | 25810281493 | committed | 2017-10-10 10:29:21.269612+08
  5. 40477719 | 40477727 | 25810281495 | committed | 2017-10-10 11:15:05.875067+08
  6. (2 rows)

5、使用脏读插件,将需要flashback的数据(连同头信息xmin,xmax)写入临时表,根据以上两种方法生成如下字段:

写入事务提交状态、事务提交时间。(xmin)

删除事务提交状态、事务提交时间。(xmax)

例如

  1. postgres=# select
  2. xid_to_txid(xmin) as xmin_txid, txid_status(xid_to_txid(xmin)) as xmin_cmstat, pg_xact_commit_timestamp(xmin) as xmin_ts,
  3. xid_to_txid(xmax) as xmax_txid, txid_status(xid_to_txid(xmax)) as xmax_cmstat, pg_xact_commit_timestamp(case xmax when 0 then null else xmax end) as xmax_ts,
  4. xmin as xmin1,xmax as xmax1,dead,oid,
  5. id -- 目标表字段
  6. from
  7. (
  8. SELECT * FROM pg_dirtyread('trac'::regclass)
  9. as t (tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean, oid oid,
  10. id int) -- 目标表字段
  11. ) t;
  12. xmin_txid | xmin_cmstat | xmin_ts | xmax_txid | xmax_cmstat | xmax_ts | xmin1 | xmax1 | dead | oid | id
  13. -------------+-------------+-------------------------------+-------------+-------------+-------------------------------+----------+----------+------+-----+----
  14. 25810281493 | committed | 2017-10-10 10:29:21.269612+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477717 | 40477750 | f | 0 | 1
  15. 25810281495 | committed | 2017-10-10 11:15:05.875067+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477719 | 40477752 | f | 0 | 2
  16. 25810281503 | aborted | | 0 | | | 40477727 | 0 | t | 0 | 2
  17. 25810281503 | aborted | | 0 | | | 40477727 | 0 | t | 0 | 2
  18. 25810281513 | committed | 2017-10-10 16:56:12.206339+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477737 | 40477752 | f | 0 | 2
  19. 25810281514 | committed | 2017-10-10 16:56:13.706233+08 | 0 | | | 40477738 | 0 | f | 0 | 3
  20. 25810281515 | committed | 2017-10-10 16:56:15.108331+08 | 0 | | | 40477739 | 0 | f | 0 | 4
  21. 25810281516 | committed | 2017-10-10 16:56:16.092184+08 | 25810281521 | committed | 2017-10-10 16:56:58.684832+08 | 40477740 | 40477745 | f | 0 | 5
  22. 25810281517 | committed | 2017-10-10 16:56:17.207356+08 | 25810281519 | committed | 2017-10-10 16:56:48.011544+08 | 40477741 | 40477743 | f | 0 | 6
  23. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 6
  24. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 6
  25. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 6
  26. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 7
  27. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 7
  28. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 7
  29. 25810281519 | committed | 2017-10-10 16:56:48.011544+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477743 | 40477752 | f | 0 | 2
  30. 25810281520 | aborted | | 0 | | | 40477744 | 0 | t | 0 | 2
  31. 25810281521 | committed | 2017-10-10 16:56:58.684832+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477745 | 40477752 | f | 0 | 2
  32. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1
  33. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1
  34. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1
  35. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1
  36. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1
  37. (23 rows)
  38. postgres=# select xmin,xmax,* from trac ;
  39. xmin | xmax | id
  40. ----------+------+----
  41. 40477738 | 0 | 3
  42. 40477739 | 0 | 4
  43. (2 rows)

1、根据pg_xlogdump找到精确的误操作xid,以及事务提交对应的时间戳。(或者使用用户提供的时间戳,大概的误操作前的时间。)

参考:

2、回退到过去的某个时间点(采用基于临时表的VIEW来展现) (根据事务提交顺序,逆序,逐个事务排除,逐个事务回退。)

  1. select * from tmp_xxx where
  2. (
  3. xmin_cmstat='committed' and xmin_ts <= '$ts'
  4. and
  5. (xmax_cmstat='committed' and xmax_ts < '$ts') is distinct from true
  6. )
  7. ;

例子

  1. select * from tmp_xxx where
  2. (
  3. xmin_cmstat='committed' and xmin_ts <= '2017-10-10 16:56:58.684832+08'
  4. and
  5. (xmax_cmstat='committed' and xmax_ts < '2017-10-10 16:56:58.684832+08') is distinct from true
  6. )
  7. ;
  8. xmin_txid | xmin_cmstat | xmin_ts | xmax_txid | xmax_cmstat | xmax_ts | xmin1 | xmax1 | dead | oid | id
  9. -------------+-------------+-------------------------------+-------------+-------------+-------------------------------+----------+----------+------+-----+----
  10. 25810281493 | committed | 2017-10-10 10:29:21.269612+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477717 | 40477750 | f | 0 | 1
  11. 25810281495 | committed | 2017-10-10 11:15:05.875067+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477719 | 40477752 | f | 0 | 2
  12. 25810281513 | committed | 2017-10-10 16:56:12.206339+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477737 | 40477752 | f | 0 | 2
  13. 25810281514 | committed | 2017-10-10 16:56:13.706233+08 | 0 | | | 40477738 | 0 | f | 0 | 3
  14. 25810281515 | committed | 2017-10-10 16:56:15.108331+08 | 0 | | | 40477739 | 0 | f | 0 | 4
  15. 25810281516 | committed | 2017-10-10 16:56:16.092184+08 | 25810281521 | committed | 2017-10-10 16:56:58.684832+08 | 40477740 | 40477745 | f | 0 | 5
  16. 25810281519 | committed | 2017-10-10 16:56:48.011544+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477743 | 40477752 | f | 0 | 2
  17. 25810281521 | committed | 2017-10-10 16:56:58.684832+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477745 | 40477752 | f | 0 | 2
  18. (8 rows)

3、找出被误操作事务 删除、更新、插入 的记录(OLD ROW(被删除、更新前的), NEW ROW(更新后的、误插入的))。

  1. select * from tmp_xxx where xmax1=? and xmax_cmstat='committed' and xmin_cmstat='committed'; -- 被某个XID删除、更新前的数据。
  2. select * from tmp_xxx where xmin1=? and xmin_cmstat='committed'; -- 被某个XID插入、更新后的数据。

例子

  1. postgres=# select * from tmp_xxx where xmax1=40477745 and xmax_cmstat='committed' and xmin_cmstat='committed';
  2. xmin_txid | xmin_cmstat | xmin_ts | xmax_txid | xmax_cmstat | xmax_ts | xmin1 | xmax1 | dead | oid | id
  3. -------------+-------------+-------------------------------+-------------+-------------+-------------------------------+----------+----------+------+-----+----
  4. 25810281516 | committed | 2017-10-10 16:56:16.092184+08 | 25810281521 | committed | 2017-10-10 16:56:58.684832+08 | 40477740 | 40477745 | f | 0 | 5
  5. (1 row)
  6. postgres=# select * from tmp_xxx where xmin1=40477745 and xmin_cmstat='committed';
  7. xmin_txid | xmin_cmstat | xmin_ts | xmax_txid | xmax_cmstat | xmax_ts | xmin1 | xmax1 | dead | oid | id
  8. -------------+-------------+-------------------------------+-------------+-------------+-------------------------------+----------+----------+------+-----+----
  9. (1 row)

flashback 可能造成的负面影响

flashback的前提,前面已经讲了,但是可能带来一些负面影响。

1、由于设置了vacuum_defer_cleanup_age,因此每次都会被触发VACUUM,扫描表,但是又有一些垃圾不能被回收;

2、可能导致表膨胀。

1、提高autovacuum_naptime,从而降低频繁扫描的概率。

2、膨胀可能无法解决。建议修改内核,实现可以仅针对重要的表设置 vacuum_defer_cleanup_age。从而避免全库膨胀。

相关知识点

相关参数 - 跟踪事务时间、延迟回收垃圾

  1. track_commit_timestamp = on # collect timestamp of transaction commit
  2. # (change requires restart)
  3. vacuum_defer_cleanup_age = 100000 # number of xacts by which cleanup is delayed

相关函数 - 事务状态、事务结束时间

https://www.postgresql.org/docs/10/static/functions-info.html

  1. txid_status(bigint)
  2. reports the commit status of a recent transaction.
  3. Applications may use it to determine whether a transaction committed or aborted
  4. when the application and database server become disconnected while a COMMIT is in progress.
  5. The status of a transaction will be reported as either in progress, committed, or aborted,
  6. provided that the transaction is recent enough that the system retains the commit status of that transaction.
  7. If is old enough that no references to that transaction survive in the system and the commit status information has been discarded,
  8. this function will return NULL. Note that prepared transactions are reported as in progress;
  9. applications must check pg_prepared_xacts if they need to determine whether the txid is a prepared transaction.

如何跟踪事务结束时间

开启事务结束时间跟踪后,会开辟一块共享内存,跟踪事务结束时间。

xid和txid的区别

xid是32位的整型,会被FREEZE,循环使用,xmin,xmax都是XID类型。通过xid可以得到事务结束时间。

txid是64位整型,不会被循环使用,通过epoch可以从xid转换为txid。通过txid可以得到事务的提交状态。

  1. /*
  2. * Export internal transaction IDs to user level.
  3. *
  4. * Note that only top-level transaction IDs are ever converted to TXID.
  5. * This is important because TXIDs frequently persist beyond the global
  6. * xmin horizon, or may even be shipped to other machines, so we cannot
  7. * rely on being able to correlate subtransaction IDs with their parents
  8. * via functions such as SubTransGetTopmostTransaction().
  9. *
  10. /* txid will be signed int8 in database, so must limit to 63 bits */
  11. #define MAX_TXID UINT64CONST(0x7FFFFFFFFFFFFFFF)
  12. /*
  13. * do a TransactionId -> txid conversion for an XID near the given epoch
  14. */
  15. static txid
  16. convert_xid(TransactionId xid, const TxidEpoch *state)
  17. {
  18. uint64 epoch;
  19. /* return special xid's as-is */
  20. if (!TransactionIdIsNormal(xid))
  21. return (txid) xid;
  22. /* xid can be on either side when near wrap-around */
  23. epoch = (uint64) state->epoch;
  24. if (xid > state->last_xid &&
  25. TransactionIdPrecedes(xid, state->last_xid))
  26. epoch--;
  27. else if (xid < state->last_xid &&
  28. TransactionIdFollows(xid, state->last_xid))
  29. epoch++;
  30. return (epoch << 32) | xid;
  31. }

我们可以自定义一个函数,将xid转换为txid。

  1. vi xid_to_txid.c
  2. #include "postgres.h"
  3. #include "fmgr.h"
  4. #include "access/xact.h"
  5. #include "access/transam.h"
  6. #include "access/xlog.h"
  7. /* Use unsigned variant internally */
  8. typedef uint64 txid;
  9. /*
  10. * Epoch values from xact.c
  11. */
  12. typedef struct
  13. {
  14. TransactionId last_xid;
  15. uint32 epoch;
  16. } TxidEpoch;
  17. PG_MODULE_MAGIC;
  18. PG_FUNCTION_INFO_V1(xid_to_txid);
  19. /*
  20. * do a TransactionId -> txid conversion for an XID near the given epoch
  21. */
  22. static txid
  23. convert_xid(TransactionId xid, const TxidEpoch *state)
  24. {
  25. uint64 epoch;
  26. /* return special xid's as-is */
  27. if (!TransactionIdIsNormal(xid))
  28. return (txid) xid;
  29. /* xid can be on either side when near wrap-around */
  30. epoch = (uint64) state->epoch;
  31. if (xid > state->last_xid &&
  32. TransactionIdPrecedes(xid, state->last_xid))
  33. epoch--;
  34. else if (xid < state->last_xid &&
  35. TransactionIdFollows(xid, state->last_xid))
  36. epoch++;
  37. return (epoch << 32) | xid;
  38. }
  39. /*
  40. * Fetch epoch data from xact.c.
  41. */
  42. static void
  43. load_xid_epoch(TxidEpoch *state)
  44. {
  45. GetNextXidAndEpoch(&state->last_xid, &state->epoch);
  46. }
  47. Datum
  48. xid_to_txid(PG_FUNCTION_ARGS)
  49. {
  50. txid val;
  51. TxidEpoch state;
  52. TransactionId xid;
  53. xid = DatumGetTransactionId(PG_GETARG_DATUM(0));
  54. load_xid_epoch(&state);
  55. val = convert_xid(xid, &state);
  56. PG_RETURN_INT64(val);
  57. }

编译

  1. gcc -O3 -Wall -Wextra -Werror -I /home/digoal/postgresql-10beta4/src/include -g -fPIC -c ./xid_to_txid.c -o xid_to_txid.o
  2. gcc -O3 -Wall -Wextra -Werror -I /home/digoal/postgresql-10beta4/src/include -g -shared xid_to_txid.o -o libxid_to_txid.so

拷贝到数据库软件LIB目录

  1. cp libxid_to_txid.so pgsql10/lib/

创建函数

  1. create or replace function xid_to_txid(xid) returns int8 as '$libdir/libxid_to_txid.so', 'xid_to_txid' language C STRICT;

测试

  1. -- 当前值
  2. xmin | xmax | xid_to_txid | txid_status | pg_xact_commit_timestamp
  3. ----------+------+-------------+-------------+-------------------------------
  4. 40477717 | 0 | 8630412309 | committed | 2017-10-10 10:29:21.269612+08
  5. 40477719 | 0 | 8630412311 | committed | 2017-10-10 11:15:05.875067+08
  6. (2 rows)
  7. -- 产生一些DML
  8. postgres=# begin;
  9. BEGIN
  10. postgres=# update trac set id =2;
  11. UPDATE 2
  12. postgres=# rollback;
  13. ROLLBACK
  14. -- 值的变化
  15. postgres=# select xmin,xmax,xid_to_txid(xmin),txid_status(xid_to_txid(xmin)),pg_xact_commit_timestamp(xmin) from trac ;
  16. xmin | xmax | xid_to_txid | txid_status | pg_xact_commit_timestamp
  17. ----------+----------+-------------+-------------+-------------------------------
  18. 40477717 | 40477727 | 8630412309 | committed | 2017-10-10 10:29:21.269612+08
  19. 40477719 | 40477727 | 8630412311 | committed | 2017-10-10 11:15:05.875067+08
  20. (2 rows)
  21. postgres=# select xmin,xmax,xid_to_txid(xmin),txid_status(xid_to_txid(xmin)),pg_xact_commit_timestamp(xmin),xid_to_txid(xmax),txid_status(xid_to_txid(xmax)),pg_xact_commit_timestamp(xmax) from trac ;
  22. xmin | xmax | xid_to_txid | txid_status | pg_xact_commit_timestamp | xid_to_txid | txid_status | pg_xact_commit_timestamp
  23. ----------+----------+-------------+-------------+-------------------------------+-------------+-------------+--------------------------
  24. 40477717 | 40477727 | 8630412309 | committed | 2017-10-10 10:29:21.269612+08 | 8630412319 | aborted |
  25. 40477719 | 40477727 | 8630412311 | committed | 2017-10-10 11:15:05.875067+08 | 8630412319 | aborted |
  26. (2 rows)
  27. -- 停库,修改epoch
  28. pg_ctl stop -m fast
  29. pg_resetwal -e 5 $PGDATA
  30. Write-ahead log reset
  31. -- 通过控制文件可以得到这个epoch
  32. pg_controldata
  33. Latest checkpoint's NextXID: 5:40477728
  34. -- 继续修改epoch
  35. pg_resetwal -e 6 $PGDATA
  36. Write-ahead log reset
  37. -- 通过控制文件可以得到这个epoch
  38. pg_controldata
  39. Latest checkpoint's NextXID: 6:40477728
  40. -- 启动
  41. pg_ctl start
  42. -- epoch修改后,txid发生了变化
  43. postgres=# select xmin,xmax,xid_to_txid(xmin),txid_status(xid_to_txid(xmin)),pg_xact_commit_timestamp(xmin),xid_to_txid(xmax),txid_status(xid_to_txid(xmax)),pg_xact_commit_timestamp(xmax) from trac ;
  44. xmin | xmax | xid_to_txid | txid_status | pg_xact_commit_timestamp | xid_to_txid | txid_status | pg_xact_commit_timestamp
  45. ----------+----------+-------------+-------------+-------------------------------+-------------+-------------+--------------------------
  46. 40477717 | 40477727 | 25810281493 | committed | 2017-10-10 10:29:21.269612+08 | 25810281503 | aborted |
  47. 40477719 | 40477727 | 25810281495 | committed | 2017-10-10 11:15:05.875067+08 | 25810281503 | aborted |
  48. (2 rows)

为什么会有EPOCH呢?因为XID是循环使用的,每一个循环都会使得EPOCH自增1。从而使得TXID可以持续增长。

《Use pg_resetxlog simulate tuple disappear within PostgreSQL》

《PostgreSQL 使用pg_xlogdump找到误操作事务号》

https://www.postgresql.org/docs/10/static/functions-info.html

《PostgreSQL 回收站功能 - 基于HOOK的recycle bin pgtrashcan》

其他

误操作后,如果又发生了DDL,例如新增字段,修改字段等。使用本文提供的闪回方法,有没有问题?

测一下就知道了,不会有问题。

  1. postgres=# alter table trac add column info text;
  2. ALTER TABLE
  3. postgres=# insert into trac values (2,'test');
  4. INSERT 0 1
  5. postgres=# select
  6. xid_to_txid(xmin) as xmin_txid, txid_status(xid_to_txid(xmin)) as xmin_cmstat, pg_xact_commit_timestamp(xmin) as xmin_ts,
  7. xid_to_txid(xmax) as xmax_txid, txid_status(xid_to_txid(xmax)) as xmax_cmstat, pg_xact_commit_timestamp(case xmax when 0 then null else xmax end) as xmax_ts,
  8. xmin as xmin1,xmax as xmax1,dead,oid,
  9. id,info -- 目标表字段
  10. from
  11. (
  12. SELECT * FROM pg_dirtyread('trac'::regclass)
  13. as t (tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean, oid oid,
  14. id int, info text) -- 目标表字段
  15. ) t;
  16. xmin_txid | xmin_cmstat | xmin_ts | xmax_txid | xmax_cmstat | xmax_ts | xmin1 | xmax1 | dead | oid | id | info
  17. -------------+-------------+-------------------------------+-------------+-------------+-------------------------------+----------+----------+------+-----+----+------
  18. 25810281493 | committed | 2017-10-10 10:29:21.269612+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477717 | 40477750 | f | 0 | 1 |
  19. 25810281495 | committed | 2017-10-10 11:15:05.875067+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477719 | 40477752 | f | 0 | 2 |
  20. 25810281503 | aborted | | 0 | | | 40477727 | 0 | t | 0 | 2 |
  21. 25810281503 | aborted | | 0 | | | 40477727 | 0 | t | 0 | 2 |
  22. 25810281513 | committed | 2017-10-10 16:56:12.206339+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477737 | 40477752 | f | 0 | 2 |
  23. 25810281514 | committed | 2017-10-10 16:56:13.706233+08 | 0 | | | 40477738 | 0 | f | 0 | 3 |
  24. 25810281515 | committed | 2017-10-10 16:56:15.108331+08 | 0 | | | 40477739 | 0 | f | 0 | 4 |
  25. 25810281516 | committed | 2017-10-10 16:56:16.092184+08 | 25810281521 | committed | 2017-10-10 16:56:58.684832+08 | 40477740 | 40477745 | f | 0 | 5 |
  26. 25810281517 | committed | 2017-10-10 16:56:17.207356+08 | 25810281519 | committed | 2017-10-10 16:56:48.011544+08 | 40477741 | 40477743 | f | 0 | 6 |
  27. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 6 |
  28. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 6 |
  29. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 6 |
  30. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 7 |
  31. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 7 |
  32. 25810281518 | aborted | | 0 | | | 40477742 | 0 | t | 0 | 7 |
  33. 25810281519 | committed | 2017-10-10 16:56:48.011544+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477743 | 40477752 | f | 0 | 2 |
  34. 25810281520 | aborted | | 0 | | | 40477744 | 0 | t | 0 | 2 |
  35. 25810281521 | committed | 2017-10-10 16:56:58.684832+08 | 25810281528 | committed | 2017-10-10 17:25:47.410793+08 | 40477745 | 40477752 | f | 0 | 2 |
  36. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1 |
  37. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1 |
  38. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1 |
  39. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1 |
  40. 25810281523 | committed | 2017-10-10 17:21:39.000214+08 | 25810281526 | committed | 2017-10-10 17:25:34.593189+08 | 40477747 | 40477750 | f | 0 | 1 |
  41. 25810281532 | committed | 2017-10-10 18:58:50.720095+08 | 0 | | | 40477756 | 0 | f | 0 | 2 | test
  42. (24 rows)

小结

本文介绍了原地闪回的一种方法:

1、新增脏读功能、新增表级vacuum_defer_cleanup_age(避免全库膨胀)功能、开启track_commit_timestamp。可以实现dml flashback(闪回)。

2、增加回收站(通过HOOK)功能,可以实现DDL flashback。

原地闪回的另一种方法:利用redo的undo内容进行闪回,这种方法可以避免膨胀的问题,回退到什么时间点,与保留的REDO文件数有关。使用redo来闪回也会引入一个问题,UNDO需要记录更多的内容,导致REDO文件内容变多。因此建议也是设置表级redo的UNDO内容。

  1. REPLICA IDENTITY
  2. This form changes the information which is written to the write-ahead log
  3. to identify rows which are updated or deleted.
  4. This option has no effect except when logical replication is in use.
  5. DEFAULT (the default for non-system tables) records the old values of the columns
  6. of the primary key, if any.
  7. USING INDEX records the old values of the columns covered by the named index,
  8. which must be unique, not partial, not deferrable, and include only columns marked NOT NULL.
  9. FULL records the old values of all columns in the row.
  10. NOTHING records no information about the old row.
  11. (This is the default for system tables.)
  12. be logged differs between the old and new versions of the row.