日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

postgresql 删除触发器_PostgreSQL:我没有带闪,不讲武德

發布時間:2024/9/27 数据库 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 postgresql 删除触发器_PostgreSQL:我没有带闪,不讲武德 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

今天有個業務的妹子問我“在嗎?”

我說什么事?

給我發個截圖,我一看!噢,原來是把數據刪除了,想讓我把數據找回來。

他說,大哥你能不能幫我。

我說可以!

很快啊,我就打開終端,一個指令就開始了。

我大E了,發現數據閃回不了。

然后十分鐘后我告訴她,搞不定了。

然后她就投訴到領導哪里去了,說她丟的數據找不回來了,DBA也搞不定。

我找到這個妹子,說:“你不講規矩,你不懂這個恢復的難度。”

她忙說對不起,我不懂規矩啊!

我說:“不講規矩,來,告狀,誣陷我20多年經驗的dba連點數據都恢復不了。這好嗎?這不好。我勸這位女同學,耗子尾汁。好好反思。

PostgreSQL如何開閃

說到閃回查詢,PostgreSQL一開始是有這個功能的,它叫Time Travel(時間旅行),這名字聽上去比閃回查詢要高大上,瞬間讓我想起了好幾部描述這類的電影,如《時間機器》、《時間旅行者的妻子》、《信條》。

我們擁有時間旅行,可以穿梭于任意的時空,然后來阻止一場災難?大多數電影都是這類的橋段,而對于數據庫來說,時間旅行也是我們拯救災難的一種方法。

時間旅行Time Travel這項技術還要追溯到PostgreSQL 6時代,但是在之后就被打入了冷宮,變成可以使用但是并不推薦。官方文網也說有性能上的影響,推薦使用觸發器替代,一直到PostgreSQL 12這個版本,才真正的把這項功能移除了。

那么怎么在PostgreSQL 12上實現呢?有很多種解決方案,其實原生的PG只是一個食材,大家可以根據這個食材,自由發揮做出各種各樣美味的料理。你可以靈活選擇適合你口味的料理(適配你的系統)。

pg_dirtyread

pg_dirtyread的工作原理比較簡單,就是從Dead Tuples中讀取數據。這得益于PostgreSQL的MVCC機制。在PostgreSQL的MVCC機制中,當更新或者刪除任何一行記錄的時候,將在內部創建新行并將舊行標記為Dead Tuples。而Pg_dirtyread就可以助我們從Dead Tuples讀出數據。但是缺點也很明顯,如果Dead Tuples被autovacuum進程清理了,也就沒數據了。

接下來我們來測試一下,下載編譯pg_dirtyread插件。

make?&&?make?install
create?extension?pg_dirtyread;

create?table?students
(
????stuno?int,
????name?varchar(50),
????age?varchar(50),
????city?varchar(50)
);

insert?into?students?(stuno,?name,?age,?city)??values?(1,?'abhiram',?22,?'allahabad');??
insert?into?students?(stuno,?name,?age,?city)??values?(2,?'alka',?20,?'ghaziabad');??
insert?into?students?(stuno,?name,?age,?city)??values?(3,?'disha',?21,?'varanasi');??
insert?into?students?(stuno,?name,?age,?city)??values?(4,?'esha',?21,?'delhi');??
insert?into?students?(stuno,?name,?age,?city)??values?(5,?'manmeet',?23,?'jalandhar');?

postgres=#?select?*?from?students;
?stuno?|??name???|?age?|???city????
-------+---------+-----+-----------
?????1?|?abhiram?|?22??|?allahabad
?????2?|?alka????|?20??|?ghaziabad
?????3?|?disha???|?21??|?varanasi
?????4?|?esha????|?21??|?delhi
?????5?|?manmeet?|?23??|?jalandhar?

對上述表做多次更新。

update?students?set?city='WuHan'?where?stuno=5;
update?students?set?age=21?where?stuno=5;
update?students?set?city='Shanghai'?where?stuno=5;

通過pg_dirtyread讀取更新前的數據。

postgres=#?SELECT?*?FROM?pg_dirtyread('students')?students(stuno?int,?name?varchar(50),age?varchar(50),city?varchar(50));
?stuno?|??name???|?age?|???city????
-------+---------+-----+-----------
?????1?|?abhiram?|?22??|?allahabad
?????2?|?alka????|?20??|?ghaziabad
?????3?|?disha???|?21??|?varanasi
?????4?|?esha????|?21??|?delhi
?????5?|?manmeet?|?23??|?jalandhar
?????5?|?manmeet?|?23??|?WuHan
?????5?|?manmeet?|?21??|?WuHan
?????5?|?manmeet?|?21??|?Shanghai

可以看到把歷史的數據都找回來了,但是很亂,它讀出了所有的歷史數據,可能你只是想恢復到其中的某一個時間點。

postgres=#?SELECT?*?FROM?pg_dirtyread('students')
postgres-#?AS?students(tableoid?oid,?ctid?tid,?xmin?xid,?xmax?xid,?cmin?cid,?cmax?cid,?dead?boolean,stuno?int,?name?varchar(50),age?varchar(50),city?varchar(50));??
?tableoid?|?ctid??|???xmin???|???xmax???|?cmin?|?cmax?|?dead?|?stuno?|??name???|?age?|???city????
----------+-------+----------+----------+------+------+------+-------+---------+-----+-----------
?20023788?|?(0,1)?|?26678735?|????????0?|????0?|????0?|?f????|?????1?|?abhiram?|?22??|?allahabad
?20023788?|?(0,2)?|?26678736?|????????0?|????0?|????0?|?f????|?????2?|?alka????|?20??|?ghaziabad
?20023788?|?(0,3)?|?26678737?|????????0?|????0?|????0?|?f????|?????3?|?disha???|?21??|?varanasi
?20023788?|?(0,4)?|?26678738?|????????0?|????0?|????0?|?f????|?????4?|?esha????|?21??|?delhi
?20023788?|?(0,5)?|?26678739?|?26678741?|????0?|????0?|?t????|?????5?|?manmeet?|?23??|?jalandhar
?20023788?|?(0,6)?|?26678741?|?26678742?|????0?|????0?|?t????|?????5?|?manmeet?|?23??|?WuHan
?20023788?|?(0,7)?|?26678742?|?26678743?|????0?|????0?|?f????|?????5?|?manmeet?|?21??|?WuHan
?20023788?|?(0,8)?|?26678743?|????????0?|????0?|????0?|?f????|?????5?|?manmeet?|?21??|?Shanghai

不過知道死元組的事務ID就可以通過pg_xact_commit_timestamp函數將xmin轉換成時間。

使用pg_xact_commit_timestamp函數,需要將參數track_commit_timestamp設置為on,修改該參數需要重啟數據庫。

postgres=#?select?(pg_xact_commit_timestamp(xmin))?from?
postgres-#?(SELECT?*?FROM?pg_dirtyread('students')?AS?students(tableoid?oid,?ctid?tid,?xmin?xid,?xmax?xid,?cmin?cid,?cmax?cid,?dead?boolean,stuno?int,?name?varchar(50),age?varchar(50),city?varchar(50)))?as?b;?
???pg_xact_commit_timestamp????
-------------------------------
?2020-11-23?15:23:48.611553+08
?2020-11-23?15:23:48.624343+08
?2020-11-23?15:23:48.6367+08
?2020-11-23?15:23:48.65629+08
?2020-11-23?15:23:48.676773+08
?2020-11-23?15:23:55.716173+08
?2020-11-23?15:23:55.729868+08
?2020-11-23?15:23:56.02215+08

這樣就可以基于時間點恢復到你想要的位置了。

可以說pg_dirtyread很好的解決了誤操作導致的數據修改刪除問題。但是它最大的缺點就是受制于autovacuum進程,如果autovacuum進程清理掉了死元組,pg_dirtyread就沒辦法工作了。所以當出現誤刪數據之后,我們第一時間就要先關閉autovacuum,然后通過下面查詢誤操作的表是否已經發生了vacuum。

select?relname,last_vacuum,?last_autovacuum,?last_analyze,?last_autoanalyze?from?pg_stat_user_tables;

最后說一點,這個方法雖好,但是不支持truncate和drop這類的ddl。

temporal_tables

temporal_tables也是一個不錯的擴展,但是它的原理和pg_dirtyread完全不同。它的原理是將我們修改或者刪除的舊行歸檔到一個歷史表中,這樣可以方便進行審計、對比。至于這個插件我覺得他們和IBM DB2的功能很接近,都需要使用一個叫時態表temporal tables技術。

我們來測試一下,下載編譯temporal_tables插件。

make?&&?make?install
create?extension?temporal_tables;

接下來我們來創建表。

create?table?students
(
????stuno?int,
????name?varchar(50),
????age?varchar(50),
????city?varchar(50)
);

建完表后,我們要增加一個sys_period列。

ALTER?TABLE?students?ADD?COLUMN?sys_period?tstzrange?NOT?NULL;

然后我們需要創建一個歷史表。

CREATE?TABLE?students_history?(LIKE?students);

最后我們要創建一個觸發器,把我們的表和歷史表關聯起來。

CREATE?TRIGGER?students_hist_trigger?BEFORE?
INSERT?OR?UPDATE?OR?DELETE?ON?students?FOR?EACH?ROW
EXECUTE?PROCEDURE?versioning('sys_period',?'students_history',?true);

插入記錄。

insert?into?students?(stuno,?name,?age,?city)??values?(1,?'abhiram',?22,?'allahabad');??
insert?into?students?(stuno,?name,?age,?city)??values?(2,?'alka',?20,?'ghaziabad');??
insert?into?students?(stuno,?name,?age,?city)??values?(3,?'disha',?21,?'varanasi');??
insert?into?students?(stuno,?name,?age,?city)??values?(4,?'esha',?21,?'delhi');??
insert?into?students?(stuno,?name,?age,?city)??values?(5,?'manmeet',?23,?'jalandhar');??

此時通過查詢,會發現sys_period列上會顯示時間。["2020-11-23 17:10:58.702324+08",)。這個格式前面代表著有效期開始時間,后面則代表有效期結束時間,這里,后面是空的,代表了無窮大。

postgres=#?select?*?from?students;
stuno?|??name???|?age?|???city????|?????????????sys_period?????????????
-------+---------+-----+-----------+------------------------------------
?????1?|?abhiram?|?22??|?allahabad?|?["2020-11-23?17:48:13.841549+08",)
?????2?|?alka????|?20??|?ghaziabad?|?["2020-11-23?17:48:13.862973+08",)
?????3?|?disha???|?21??|?varanasi??|?["2020-11-23?17:48:13.874852+08",)
?????4?|?esha????|?21??|?delhi?????|?["2020-11-23?17:48:13.891388+08",)
?????5?|?manmeet?|?21??|?Shanghai??|?["2020-11-23?17:51:22.613059+08",)

我們對表進行更新操作,此時查詢students_history就會顯示我們的歷史數據。

update?students?set?city='WuHan'?where?stuno=5;
update?students?set?age=21?where?stuno=5;
update?students?set?city='Shanghai'?where?stuno=5;

postgres=#?select?*?from?students_history;?
stuno?|??name???|?age?|???city????|????????????????????????????sys_period?????????????????????????????
-------+---------+-----+-----------+-------------------------------------------------------------------
?????5?|?manmeet?|?23??|?jalandhar?|?["2020-11-23?17:48:13.916846+08","2020-11-23?17:48:31.964398+08")
?????5?|?manmeet?|?23??|?WuHan?????|?["2020-11-23?17:48:31.964398+08","2020-11-23?17:50:30.014874+08")
?????5?|?manmeet?|?21??|?WuHan?????|?["2020-11-23?17:50:30.014874+08","2020-11-23?17:51:22.613059+08")

雖然能顯示數據,但是和我們想要的差距還是有點大。因為如上面所示,數據還是很紊亂的。想要查詢到指定的時間點還是很困難的。不過根據歷史視圖,我們知道我們在下面三個時間點更新了數據。分別是17:48:13 17:50:30 17:51:22

我們可以在創建一個視圖。

CREATE?VIEW?students_with_history?AS
SELECT?*?FROM?students
UNION?ALL
SELECT?*?FROM?students_history;

然后執行下面操作,我就想看看在17:49分應該是顯示那條數據,這里要顯示第一次做update的結果。

postgres=#?SELECT?*?FROM?students_with_history
postgres-#?WHERE?stuno?=?5?AND?sys_period?@>?'2020-11-23?17:49:00'::timestamptz;
stuno?|??name???|?age?|?city??|????????????????????????????sys_period?????????????????????????????
-------+---------+-----+-------+-------------------------------------------------------------------
?????5?|?manmeet?|?23??|?WuHan?|?["2020-11-23?17:48:31.964398+08","2020-11-23?17:50:30.014874+08")
(1?row)

可以看到結果完全正確。換成17點51分在看看,這里顯示了第二次做update的結果。

postgres=#?SELECT?*?FROM?students_with_history
postgres-#???WHERE?stuno?=?5?AND?sys_period?@>?'2020-11-23?17:51:00'::timestamptz?;
?stuno?|??name???|?age?|?city??|????????????????????????????sys_period?????????????????????????????
-------+---------+-----+-------+-------------------------------------------------------------------
?????5?|?manmeet?|?21??|?WuHan?|?["2020-11-23?17:50:30.014874+08","2020-11-23?17:51:22.613059+08")
(1?row)

以上的操作方法就像Oracle中的語法as of timestamp一樣。而AS OF SYSTEM TIME語法是SQL 2011的標準。

而wiki上也有一篇文章詳細的描述了PostgreSQL實現SQL 2011的方法和建議,實現的原理和temporal_tables差不多,但是它多出來了truncate的恢復。其實temporal_tables要實現truncate也很簡單,自己做一個truncate的觸發器就行了。

SQL2011Temporal

衍生版PG

當前現在市面上有一些衍生版的PG,比如CockroachDB。提供了SQL 2011中的AS OF SYSTEM TIME語法。

有興趣的同學可以看看蟑螂數據庫是怎么實現SQL:2011標準的。

Time-Travel Queries: SELECT witty_subtitle FROM THE FUTURE

總結

通過驗證可以看出PostgreSQL打開閃回功能還是比較復雜的,它不像其他數據庫內置了這個功能。需要我們自己找第三方插件來實現。而大多數第三方插件都是基于觸發器實現的。而觸發器的往往會存在一些開銷。同時還要在原表上增加一個時間區間的字段。所以還是推薦使用pg_dirtyread來拯救您誤刪除的數據啊喂。

總結

以上是生活随笔為你收集整理的postgresql 删除触发器_PostgreSQL:我没有带闪,不讲武德的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美视频亚洲视频 | 岛国大片在线 | 女人毛片视频 | 欧美三级欧美一级 | jizzz18| 亚洲AV成人无码网站天堂久久 | 国产精品夜夜夜爽张柏芝 | 欧美456| 久草高清视频 | 影音先锋中文字幕资源 | 在线观看日本中文字幕 | 日本一区二区三区视频在线观看 | 无码av免费毛片一区二区 | 69精品视频 | 国产精品v | 免费男女乱淫真视频免费播放 | 91香蕉在线视频 | 影音先锋二区 | 久久福利影院 | 国产精品久久久久久久av福利 | 精品在线不卡 | 国产三级全黄 | 日韩视频精品在线 | 亚洲播播 | 大奶在线播放 | 精品欧美黑人一区二区三区 | 国产大片一区二区三区 | 尤物网站在线播放 | 韩国伦理在线 | 手机看片日韩日韩 | av激情网站| 亚洲福利国产 | 天天插天天搞 | 精品国产午夜福利在线观看 | 产乳奶汁h文1v1 | av国语| 麻豆网址 | 日韩欧美www| 性感美女被爆操 | 黄色av片三级三级三级免费看 | 一级香蕉视频在线观看 | 国产黄色91 | 在线观看高清视频 | 九九精品网 | 国产色拍 | 午夜资源网 | 一区二区三区小视频 | 91视频毛片 | 中国黄色一级毛片 | 丝袜一区二区三区四区 | 国产无玛| jlzzjlzz亚洲日本少妇 | 四虎av影院 | 日韩激情电影在线 | 日本三级在线 | 国产日日操 | 亚洲精品国产精品国自产网站按摩 | 亚洲黄色网址大全 | 丁香六月久久 | 国产精品日本 | 国产精选中文字幕 | 国产精品果冻传媒潘 | 丰满熟女人妻一区二区三 | 九九综合九九综合 | www插插插无码免费视频网站 | 神马影院午夜伦理片 | 五月婷婷开心 | 91中文字幕网| 五月综合视频 | 亚洲色图在线观看视频 | 免费国产在线视频 | 日韩欧美无 | 加勒比久久综合 | 中文字幕国产精品 | 国产女人18毛片水真多18精品 | 色91av| 欧美日韩国产传媒 | 亲子乱aⅴ一区二区三区 | 色哟哟免费在线观看 | 6090伦理 | 精品少妇人妻av免费久久洗澡 | 一区二区三区在线视频播放 | 小优视频污| 偷拍久久久 | 色婷婷国产精品久久包臀 | 69国产在线 | 日韩一区二区三区在线观看视频 | 尤物视频在线观看国产 | 精品久久久久中文慕人妻 | 网站在线看| 亚洲23p| 亚洲视频在线观看一区 | brazzers欧美一区二区 | 污视频在线播放 | 日韩aaa | 九九热在线观看视频 | 欧洲一区二区 | 大尺度床戏揉捏胸视频 | 日韩一区av在线 |