云贝教育 |【技术文章】PostgreSQL中误删除数据怎么办(一)

原文链接:【PostgreSQL】PostgreSQL中误删除数据怎么办(一) - 课程体系 - 云贝教育 (yunbee.net)

在我们学习完PG的MVCC机制之后,对于DML操作,被操作的行其实并未被删除,只能手工vacuum或自动vacuum触发才会清理掉这些无效数据,也就是死元组。

基于这种机制,在发生死元组清理动作之前,只需要将其中不可见的行中的数据解析出来,或者发生脏读,就可以获取到误删除的数据。虽然PG不支持脏读,但今天介绍的pg_dirtyread插件,可以实现脏读。

一、安装pg_dirtyread

下载地址

GitHub - df7cb/pg_dirtyread: Read dead but unvacuumed tuples from a PostgreSQL relation

这个网页上有详细的安装说明

编译安装

unzip pg_dirtyread-master.zip
cd pg_dirtyread-master/
make
make install

二、使用示例

2.1、在对应库创建EXTENSION
create extension pg_dirtyread ;

2.2、创建表并禁用autovacuum
testdb=# CREATE TABLE t1 (id int, name text);
CREATE TABLE
2.3、插入并通过heap_page_items查看数据
testdb=# INSERT INTO t1 VALUES (1, 'aaa'), (2, 'bbb'),(3,'ccc');
INSERT 0 3
testdb=#
testdb=# SELECT lp as tuple, t_xmin, t_xmax, t_field3 as t_cid, t_ctid,t_data FROM heap_page_items(get_raw_page('t1', 0));tuple | t_xmin | t_xmax | t_cid | t_ctid | t_data
-------+--------+--------+-------+--------+----------------------------1 |   1104 |      0 |     0 | (0,1)  | \x0100000000000000096161612 |   1104 |      0 |     0 | (0,2)  | \x0200000000000000096262623 |   1104 |      0 |     0 | (0,3)  | \x030000000000000009636363
(3 rows)
2.4、删除数据
testdb=# DELETE FROM t1 WHERE id = 1;
DELETE 1
testdb=# DELETE FROM t1 WHERE id = 2;
DELETE 1testdb=# SELECT lp as tuple, t_xmin, t_xmax, t_field3 as t_cid, t_ctid,t_data FROM heap_page_items(get_raw_page('t1', 0));tuple | t_xmin | t_xmax | t_cid | t_ctid | t_data
-------+--------+--------+-------+--------+----------------------------1 |   1104 |   1105 |     0 | (0,1)  | \x0100000000000000096161612 |   1104 |   1106 |     0 | (0,2)  | \x0200000000000000096262623 |   1104 |      0 |     0 | (0,3)  | \x030000000000000009636363
(3 rows)

这里发现被删除的数据还在块中

2.5、 发现数据被误删除后第一时间关掉表上的vacuum

这一步很关键!!!

这一步很关键!!!

这一步很关键!!!

ALTER TABLE t1 SET (
autovacuum_enabled = false, toast.autovacuum_enabled = false
);

2.6、查看表vacuum情况
testdb=# \x
Expanded display is on.
testdb=# select * from pg_stat_all_tables where relname='t1';
-[ RECORD 1 ]-------+-------
relid               | 49546
schemaname          | public
relname             | t1
seq_scan            | 3
seq_tup_read        | 6
idx_scan            |
idx_tup_fetch       |
n_tup_ins           | 3
n_tup_upd           | 0
n_tup_del           | 2
n_tup_hot_upd       | 0
n_live_tup          | 1
n_dead_tup          | 2
n_mod_since_analyze | 5
n_ins_since_vacuum  | 3
last_vacuum         |
last_autovacuum     |
last_analyze        |
last_autoanalyze    |
vacuum_count        | 0
autovacuum_count    | 0
analyze_count       | 0
autoanalyze_count   | 0

last_vacuum和last_autovacuum都是空的,表示还未被vacuum过。

2.7、使用pg_dirtyread查看表,dead为t表示数据已 经删除
testdb=# SELECT * FROM pg_dirtyread('t1')
AS t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boole an,id int, name text);tableoid | ctid  | xmin | xmax | cmin | cmax | dead | id | name
----------+-------+------+------+------+------+------+----+------49546 | (0,1) | 1104 | 1105 |    0 |    0 | t    |  1 | aaa49546 | (0,2) | 1104 | 1106 |    0 |    0 | t    |  2 | bbb49546 | (0,3) | 1104 |    0 |    0 |    0 | f    |  3 | ccc
(3 rows)

删除数据后,需要查询一下,pg_dirtyread中的dead列才会更新。也就是pg_dirtyread需要扫描一次表中的page才知道该行是不是被修改过。

testdb=# delete from t1;
DELETE 3testdb=# SELECT * FROM pg_dirtyread('t1')
AS t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id int, name text);
tableoid | ctid | xmin | xmax | cmin | cmax | dead | id | name
----------+-------+------+------+------+------+------+-----+-----
49541 | (0,1) | 1102 | 1108 | 0 | 0 | f | 1 | aaa
49541 | (0,2) | 1102 | 1108 | 0 | 0 | f | 2 | bbb
49541 | (0,3) | 1102 | 1108 | 0 | 0 | f | 3 | ccc
(3 rows)testdb=# select * from t1;
id | name
-----+-----
(0 rows)testdb=# SELECT * FROM pg_dirtyread('t1')
AS t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id int, name text);
tableoid | ctid | xmin | xmax | cmin | cmax | dead | id | name
----------+-------+------+------+------+------+------+-----+-----
49541 | (0,1) | 1102 | 1108 | 0 | 0 | t | 1 | aaa
49541 | (0,2) | 1102 | 1108 | 0 | 0 | t | 2 | bbb
49541 | (0,3) | 1102 | 1108 | 0 | 0 | t | 3 | ccc
(3 rows)
2.8 恢复到某个时间

如果做不完全恢复,即恢复数据到某个时刻,需要使用函数pg_xact_commit_timestamp将事务ID进行转换。

testdb=# alter system set track_commit_timestamp=on;
ALTER SYSTEM#删除一条数据
testdb=# select * from t1;
id | name
----+------
5 | EEE
(1 row)testdb=# delete from t1;
DELETE 1#查看删除时间
testdb=# SELECT pg_xact_commit_timestamp(xmin) xmin_time
,pg_xact_commit_timestamp(xmax) xmax_time
,*
FROM pg_dirtyread('t1')
AS t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id int, name text)
where xmax<>0;
-[ RECORD 1 ]----------------------------
xmin_time | 2023-12-03 16:27:03.830358+08
xmax_time | 2023-12-06 10:10:29.115887+08
tableoid | 49776
ctid | (0,2)
xmin | 7207
xmax | 7235
cmin | 0
cmax | 0
dead | f
id | 5
name | EEE

xmax_time 就是数据具体删除时间

2.9、pg_dirtyread还支持被删除的列
testdb=# select * from t1;
id | name
----+------
3 | ccc
(1 row)testdb=#
testdb=# ALTER TABLE t1 DROP COLUMN name;
ALTER TABLE
testdb=# SELECT * FROM pg_dirtyread('t1') t1(id int, dropped_2 text);
id | dropped_2
----+-----------
1 | aaa
2 | bbb
3 | ccc
3 | ccc
(4 rows)testdb=# select * from t1;
id
----
3
(1 row)

三、如果表上已经发生了vacuum

3.1、对表进行vacuum回收死元组
postgres=# vacuum t1;
VACUUM
3.2、查看块中的数据被清理
testdb=# SELECT lp as tuple, t_xmin, t_xmax, t_field3 as t_cid, t_ctid,t_data F
ROM heap_page_items(get_raw_page('t1', 0));
tuple | t_xmin | t_xmax | t_cid | t_ctid | t_data
-------+--------+--------+-------+--------+----------------------------1 |        |        |       |        |2 |        |        |       |        |3 |        |        |       |        |4 |   1110 |      0 |     0 |  (0,4) | \x030000000000000009636363
(4 rows)

3.3、再次用pg_dirtyread查看死元组的数据已经被清理了

testdb=# \x
Expanded display is on.
testdb=# select * from pg_stat_all_tables where relname='t1';
-[ RECORD 1 ]-------+------------------------------
relid | 49546
schemaname | public
relname | t1
seq_scan | 8
seq_tup_read | 33
idx_scan |
idx_tup_fetch |
n_tup_ins | 4
n_tup_upd | 0
n_tup_del | 3
n_tup_hot_upd | 0
n_live_tup | 1
n_dead_tup | 0
n_mod_since_analyze | 7
n_ins_since_vacuum | 0
last_vacuum | 2023-12-01 14:55:44.099392+0821 last_autovacuum |
last_analyze |
last_autoanalyze |
vacuum_count | 1
autovacuum_count | 0
analyze_count | 0
autoanalyze_count | 0testdb=# SELECT * FROM pg_dirtyread('t1') t1(id int, dropped_2 text);
id | dropped_2
----+-----------
3 | ccc
(1 row)

这种场景下,就无法通过脏块或解析死元组中的数据信息来恢复数据库,下一篇介绍WALMINER恢复误删除的数据。

总结

如果不小心误删除了数据,可以通过特殊手段来恢复数据的,具体恢复步骤如下:

1. 对表执行禁用vacuum(特别强调,这一步非常重要)

ALTER TABLE t1 SET (autovacuum_enabled = false, toast.autovacuum_enabled = false);

2. 使用pg_dirtyread插件查询被删除的数据,同时将数据抽取到中间表

create table t1_bak select id ,name from ((SELECT * FROM pg_dirtyread('t1')
AS t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id int, name text))) as foo;

另外,如何要找的数据己被vacuum,还可以通过分析数据具体被删除的时间,然后通过WalMiner解析wal日志,找到对应的时间点,生成undo sql(如果执行的delete,undo sql就是insert语句)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/207454.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【分享】我想上手机器学习

目录 前言 一、理解机器学习 1.1 机器学习的目的 1.2 机器学习的模型 1.3 机器学习的数据 二、学习机器学习要学什么 2.1 学习机器学习的核心内容 2.2 怎么选择模型 2.3 怎么获取训练数据 2.4 怎么训练模型 三、机器学习的门槛 3.1 机器学习的第一道门槛 3.2 机器…

最新版IDEA专业版大学生申请免费许可证教学(无需学校教育邮箱+官方途径+非破解手段)

文章目录 前言1. 申请学籍在线验证报告2. 进入IDEA官网进行认证3. 申请 JB (IDEA) 账号4. 打开 IDEA 专业版总结 前言 当你进入本篇文章时, 你应该是已经遇到了 IDEA 社区版无法解决的问题, 或是想进一步体验 IDEA 专业版的强大. 本文是一篇学生申请IDEA免费许可证的教学, 在学…

unity 2d 入门 飞翔小鸟 小鸟碰撞 及死亡(九)

1、给地面&#xff0c;柱体这种添加2d盒装碰撞器&#xff0c;小鸟移动碰到就不会动了 2、修改小鸟的脚本&#xff08;脚本命名不规范&#xff0c;不要在意&#xff09; using System.Collections; using System.Collections.Generic; using UnityEngine;public class Fly : Mo…

kafka高吞吐、低延时、高性能的实现原理

作者&#xff1a;源码时代-Raymon老师 Kafka的高吞吐、低延时、高性能的实现原理 Kafka是大数据领域无处不在的消息中间件&#xff0c;目前广泛使用在企业内部的实时数据管道&#xff0c;并帮助企业构建自己的流计算应用程序。Kafka虽然是基于磁盘做的数据存储&#xff0c;但…

可信固件-M (TF-M)

概述&#xff1a; 参考: Trusted Firmware-M Documentation — Trusted Firmware-M v2.0.0 documentation 开源代码托管&#xff1a; trusted-firmware-m.git - Trusted Firmware for M profile Arm CPUs STM32 U5支持TF-M : STM32U5 — Trusted Firmware-M v2.0.0 document…

Meta Platforms推出Imagine:基于Emu的免费AI文本到图像生成器服务

Meta Platform是Facebook、Instagram 和 WhatsApp 的母公司&#xff0c;也是领先的开源AI人工智能大语言模型 Llama 2的创建者。Meta Platforms 推出了一个名为 Imagine 的独立文本到图像 AI 生成器服务。Imagine 是基于 Meta 自己的 AI 模型 Emu 构建的&#xff0c;Emu 是在11…

循环结构中 break、continue、return 和exit() 的区别

循环结构中 break、continue、return 和exit() 的区别 文章目录 循环结构中 break、continue、return 和exit() 的区别一、break语句二、continue语句三、return 语句四、exit() 函数 说明&#xff1a;本文内容参考牟海军 著《C语言进阶&#xff1a; 重点、难点与疑点解析》&a…

HTML程序大全(1):简易计算器

HTML代码&#xff0c;主要创建了几个按钮。 <div class"container"><div class"output" id"output">0</div><button class"button" onclick"clearOutput()" id"clear">C</button>…

C#调用win10系统自带软键盘的方法

上次做了个笔记是关于调用windows系统自带的触摸键盘的方法&#xff1a;C#调用Windows系统自带触摸键盘的方法_c# 虚拟键盘-CSDN博客 除了调用触摸键盘&#xff0c;我们也可以通过调用win10的自带软键盘作为输入途径。 方法很简单。 1、添加using System.Diagnostics引用。 …

选自《洛谷深入浅出进阶篇》——欧拉函数+欧拉定理+扩展欧拉定理

欧拉函数&#xff1a; 欧拉函数定义&#xff1a; 1~n中与n互质的数的个数。 比如 欧拉函数是积性函数&#xff1a;&#xff08;也就是&#xff09;当 n与m互质的时候&#xff1a; 由算术基本定理&#xff0c;我们可以设n&#xff0c;那么我们只要计算出的取值就能求出的取…

5组10个共50个音频可视化效果PR音乐视频制作模板

我们常常看到的图形跟着音乐跳动&#xff0c;非常有节奏感&#xff0c;那这个是怎么做到的呢&#xff1f;5组10个共50个音频可视化效果PR音乐视频制作模板满足你的制作需求。 PR音乐模板|10个音频可视化视频制作模板05 https://prmuban.com/36704.html 10个音频可视化视频制作…

linux下查看文件当下的所有文件的大小和查找大文件

要查询一个文件夹下面所有文件的总大小&#xff0c;您可以使用 du 命令配合一些参数。如果您只关心总大小&#xff0c;而不是各个子文件夹或文件的大小&#xff0c;可以使用以下命令&#xff1a; du -sh /path/to/your/directory在这个命令中&#xff1a; du 是磁盘使用情况的…

设计师福利!免费实用的7款Figma插件,让你的工作事半功倍!

如今&#xff0c;Figma已经成为主流的原型和数字设计软件之一&#xff0c;许多UI设计师和设计团队开始选择使用Figma。随着Figma的快速更新和迭代&#xff0c;Figma插件库变得越来越丰富。如果使用得当&#xff0c;将有助于提高您的设计效率。本文将介绍7个工作中非常实用的Fig…

echarts词云图echarts-wordcloud使用方法

1、echarts5.0以下的版本使用 echarts-wordcloud 1.0 的词云 1. 安装 wordCloud 1.0 依赖包npm install echarts-wordcloud12. man.js 注入import echarts-wordcloud 2、echarts5.0及以上的下载 echarts-wordcloud 2.0 版本 注意&#xff1a;npm install echarts-wordcloud …

微软发布Orca2,“调教式”教会小规模大语言模型如何推理!

我们都知道在大多数情况下&#xff0c;语言模型的体量和其推理能力之间存在着正相关的关系&#xff1a;模型越大&#xff0c;其处理复杂任务的能力往往越强。 然而&#xff0c;这并不意味着小型模型就永远无法展现出色的推理性能。最近&#xff0c;奶茶发现了微软的Orca2公开了…

自动化操作脚本

文章目录 vbsopenCV pyautogui vbs SSH连接并执行指令操作 Dim WshShell Set WshShellWScript.CreateObject("WScript.Shell") WshShell.Run "cmd.exe" WScript.Sleep 1000 WshShell.SendKeys "ssh xcmg10.27.40.103" WshShell.SendKeys &qu…

xxl-job详解

目录 1、xxl-job介绍1.1 xxl-job的原理1.1.1 执行器的注册和发现1.1.2 调度中心调用执行器 1.2 quartz和xxl-job对比 2、快速入门2.1 下载并启动2.2 在调度中心新增定时任务2.3 任务运行模式(BEAN、GLUE)2.4 xxl-job的总结 3、后端专属技术群 1、xxl-job介绍 ​ xxl-job是一个…

Python源码30:海龟画图turtle画紫色的小熊

turtle模块是一个Python的标准库之一&#xff0c;它提供了一个基于Turtle graphics的绘图库。Turtle graphics是一种流行的绘图方式&#xff0c;它通过控制一个小海龟在屏幕上移动来绘制图形。 turtle模块可以让您轻松地创建和控制海龟图形&#xff0c;从而帮助您学习Python编…

Qt12.8

使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是否为…

lv11 嵌入式开发 中断控制器14

目录 1 中断控制器 ​编辑 2 Exynos4412下的中断控制器 2.1 概述 2.2 特征 ​编辑 2.3 中断状态 2.4 中断类型 2.5 中断控制器GIC中断表 3 中断控制器寄存器详解 3.1 ICDDCR&#xff08;Interrupt Controller Distributor Control Register&#xff09; 3.2 ICDISER…