使用軟件遇到問題可先更新代碼(歡迎提交bug)~~node
開發羣組:811105058歡迎任何使用者git
XlogMiner是從PostgreSQL的WAL(write ahead logs)日誌中解析出執行的SQL語句的工具,並能生成出對應的undo SQL語句。此版本使用限制較大,須要將wal級別設置爲logical,並且須要將表設置爲IDENTITY FULL模式。這會加重wal日誌的膨脹,下降數據庫性能。爲迎合PG日誌名稱的改變,現將XlogMiner更名爲WalMiner。新的開源地址爲:https://gitee.com/movead/XLogMinersql
1.WalMiner支持解析minimal級別以上的任何wal日誌級別。數據庫
2.無需將表設置爲IDENTITY FULL模式。bash
3.增長對系統表修改的wal記錄的解析。工具
4.修復發生relfilenode變化後,異庫解析失敗的bug。post
walminer能夠完整的解析出給定的wal日誌中第一個checkpoint點以後的全部wal記錄。第一個checkpoint點以前的delete和update記錄可能會解析失敗,以下。性能
UPDATE "public"."t1" SET VALUES(NULL) (NOTICE:wal is not enought.);
若是必定須要將此記錄解析出來,那麼只須要增長更早的wal日誌便可。測試
代碼下載地址:https://gitee.com/movead/XLogMiner/releasesui
編譯安裝:將下載的代碼中的walminer目錄放置到數據庫代碼的contrib目錄下,執行make;make install
[lichuancheng@IP43 walminer]$ pwd /work/src/lichuancheng/postgresql-11.1/contrib/walminer [lichuancheng@IP43 walminer]$ make;make install
postgres=# create extension walminer; CREATE EXTENSION postgres=#
postgres=# create table t2(i int,j int, k varchar); CREATE TABLE postgres=# insert into t2 values(1,1,'qqqqqq'); INSERT 0 1 postgres=# insert into t2 values(2,2,'wwwwww'); INSERT 0 1 postgres=# insert into t2 values(3,3,'eeeee'); INSERT 0 1 postgres=# update t2 set k = '1111qqqqq' where i = 1; UPDATE 1 postgres=# delete from t2 where j = 2; DELETE 1 postgres=# insert into t2 values(4,4,'44444rrrrrr'); INSERT 0 1 postgres=# select pg_walfile_name(pg_current_wal_lsn()); pg_walfile_name -------------------------- 00000001000000000000000A (1 row) postgres=# select pg_switch_wal(); pg_switch_wal --------------- 0/A003508 (1 row) postgres=#
手動備份這個須要解析的wal日誌(此處我沒有開歸檔,作這個手動備份防止wal日誌被數據庫移除)
[lichuancheng@IP43 pg_wal]$ cp 00000001000000000000000A 111/ [lichuancheng@IP43 pg_wal]$
(wal日誌能夠放置在任意位置,也可同時指定多個wal日誌)
postgres=# select walminer_wal_add('pg_wal/111/00000001000000000000000A'); NOTICE: Get data dictionary from current database. walminer_wal_add -------------------- 1 file add success (1 row)
解析方法1: postgres=# select walminer_start('NULL','NULL',0,0); walminer_start --------------------- walminer sucessful! (1 row) 解析方法2:(此種解析在$PGDATA/walminer/temp目錄下會記錄系統表的變動狀況) postgres=# select walminer_start('NULL','NULL',0,0,true); walminer_start --------------------- walminer sucessful!
postgres=# \x Expanded display is on. postgres=# select record_database,record_user,op_text,op_undo from walminer_contents; -[ RECORD 1 ]---+------------------------------------------------------------------------------------------------------ record_database | postgres record_user | lichuancheng op_text | INSERT INTO "public"."t2"("i", "j", "k") VALUES(1, 1, 'qqqqqq'); op_undo | DELETE FROM "public"."t2" WHERE "i"=1 AND "j"=1 AND "k"='qqqqqq' AND ctid = '(0,1)'; -[ RECORD 2 ]---+------------------------------------------------------------------------------------------------------ record_database | postgres record_user | lichuancheng op_text | INSERT INTO "public"."t2"("i", "j", "k") VALUES(2, 2, 'wwwwww'); op_undo | DELETE FROM "public"."t2" WHERE "i"=2 AND "j"=2 AND "k"='wwwwww' AND ctid = '(0,2)'; -[ RECORD 3 ]---+------------------------------------------------------------------------------------------------------ record_database | postgres record_user | lichuancheng op_text | INSERT INTO "public"."t2"("i", "j", "k") VALUES(3, 3, 'eeeee'); op_undo | DELETE FROM "public"."t2" WHERE "i"=3 AND "j"=3 AND "k"='eeeee' AND ctid = '(0,3)'; -[ RECORD 4 ]---+------------------------------------------------------------------------------------------------------ record_database | postgres record_user | lichuancheng op_text | UPDATE "public"."t2" SET "k" = '1111qqqqq' WHERE "i"=1 AND "j"=1 AND "k"='qqqqqq'; op_undo | UPDATE "public"."t2" SET "k" = 'qqqqqq' WHERE "i"=1 AND "j"=1 AND "k"='1111qqqqq' AND ctid = '(0,4)'; -[ RECORD 5 ]---+------------------------------------------------------------------------------------------------------ record_database | postgres record_user | lichuancheng op_text | DELETE FROM "public"."t2" WHERE "i"=2 AND "j"=2 AND "k"='wwwwww'; op_undo | INSERT INTO "public"."t2"("i", "j", "k") VALUES(2, 2, 'wwwwww'); -[ RECORD 6 ]---+------------------------------------------------------------------------------------------------------ record_database | postgres record_user | lichuancheng op_text | INSERT INTO "public"."t2"("i", "j", "k") VALUES(4, 4, '44444rrrrrr'); op_undo | DELETE FROM "public"."t2" WHERE "i"=4 AND "j"=4 AND "k"='44444rrrrrr' AND ctid = '(0,5)'; postgres=#
可使用測試數據庫解析生產庫的wal日誌。
(1)須要使用select walminer_build_dictionary(PATH);在生產庫生成數據字典,而後將生成的數據字典和須要解析的wal日誌放到測試庫能夠獲取的路徑。
(2)在測試庫使用select walminer_load_dictionary(PATH);加載數據字典
(3)指定wal日誌->執行解析->查看解析結果
具體使用方法在開源代碼中的readme中查看。
1.本版本只解析DML語句,不處理DDL語句
將來改動:DDL語句的解析已放入todolist,可能會逐步支持各類DDL語句
2.執行了刪除表、truncate表、更改表的表空間、更改表字段的類型、vacuum full,這樣的DDL語句後,發生DDL語句以前的此表相關的DML語句不會再被解析。
應對措施:建議在執行表結構變動以前,先保存一份數據字典,用來保證能夠解析歷史wal日誌。
將來改動:如今已經考慮在walminer內增長保存數據字典的功能
3.解析結果依賴於數據字典。(舉例:建立表t1,全部者爲user1,可是中間將全部者改成user2。那解析結果中,全部t1相關操做全部者都將標示爲user2)
應對措施:建議在執行表結構變動以前,先保存一份數據字典,用來保證能夠解析歷史wal日誌。
將來改動:如今已經考慮在walminer內增長保存數據字典的功能
4.解析結果中undo字段的ctid屬性是發生變動「當時」的值,若是由於vacuum等操做致使ctid發生變動,這個值將不許確。對於有可能存在重複行的數據,
咱們須要經過這個值肯定undo對應的tuple條數,不表明能夠直接執行該undo語句。
5.執行了表字段drop的DDL語句後,發生DDL語句以前的這個字段相關的值都會被解析爲encode('AD976BC56F',hex)的形式,另外自定義類型也會解析爲這種形式
6.只能解析與數據字典時間線一致的wal文件
7.WalMiner是我的出品,暫時未進行全面測試。
8.[20190309新增]不建議使用walminer解析大宗copy語句(在同一個事務中插入大量數據行)產生的wal日誌,
這會致使解析過程當中的效率低下和內存佔用太高。
舊版本的工具xlogminer的解析來源是當前wal record所記錄的"變動點"。它不會從FPW裏的page裏獲取數據進行wal記錄的解析。而新版本的walminer不只能夠解析當前wal記錄的FPW,並且還對解析過程當中出現的全部FPW進行記錄和redo。所以walminer能夠解析低級別的wal日誌,能夠不須要將表設置爲DENTITY FULL模式。
以下圖所示,咱們加載了從000000030000075100000050開始的不少wal日誌。000000030000075100000050到00000003000007510000005A的wal日誌可能會由於它依賴的wal日誌不足而沒法徹底解析(表現爲一些DML記錄沒有具體數據),在提示時間或LSN(2019-03-21 13:57:46+08 or 751/5a711300)以後的數據會徹底解析。
發現bug或者有好的建議能夠經過郵箱(lchch1990@sina.cn)聯繫我。