事務(wù)管理 學(xué)習如何通過(guò)收回具體的事務(wù)及其依賴(lài)項來(lái)識別并回滾時(shí)間。 Oracle 企業(yè)管理器中的 LogMiner 界面 LogMiner 是 Oracle 數據庫中一個(gè)經(jīng)常受到忽視但功能卻非常強大的工具。它可用于從重做日志文件中提取 DML 語(yǔ)句 — 引發(fā)事務(wù)的初始 SQL 以及甚至能取消事務(wù)的 SQL。(有關(guān) LogMiner 的介紹及其工作方式,請參閱我在 Oracle 雜志上發(fā)表的文章“挖掘線(xiàn)索”。)至今為止,這一功能強大的工具由于缺少較簡(jiǎn)單的界面而得不到普遍認可。然而,在 Oracle 數據庫 11g 中, Oracle 企業(yè)管理器具有一個(gè)使用 LogMiner 從重做日志提取事務(wù)的圖形界面,這為使用這一工具檢查和回滾事務(wù)帶來(lái)了極大的便利。(注:與以前的版本相同,如果愿意,您可以繼續使用 DBMS_LOGMNR 程序包執行命令行驅動(dòng)的日志挖掘。) 下面我們來(lái)看一個(gè)示例。要啟用日志挖掘,您只需針對數據庫或至少是針對表啟用的小型追加日志。閃回事務(wù)需要主鍵日志。要針對整個(gè)數據庫啟用它,請執行以下命令: SQL> alter database add supplemental log data; Database altered. SQL> alter database add supplemental log data (primary key) columns; Database altered. 現在,請看以下由某個(gè)應用程序針對數據庫執行的語(yǔ)句: SQL> insert into res values (100002,sysdate,12,1); 1 row created. SQL> commit; Commit complete. SQL> update res set hotel_id = 13 where res_id = 100002; 1 row updated. SQL> commit; Commit complete. SQL> delete res where res_id = 100002; 1 row deleted. SQL> commit; Commit complete. 仔細觀(guān)察這些語(yǔ)句:每個(gè)語(yǔ)句后都有一個(gè)提交語(yǔ)句,這表明每個(gè)語(yǔ)句都是一個(gè)事務(wù)?,F在讓我們看一下如何使用 Oracle 數據庫 11g 數據庫控制中的 LogMiner 檢查事務(wù)。 在企業(yè)管理器屏幕中,從數據庫主頁(yè)進(jìn)入 Availability 選項卡。 單擊 Manage 下的 View and Manage Transactions。LogMiner 主界面顯示,如下圖所示: 您可以輸入具體的時(shí)間范圍或 SCN 范圍來(lái)搜索事務(wù)。在上圖中,我已經(jīng)在 Query Time Range 中輸入了一個(gè)時(shí)間范圍進(jìn)行搜索。在 Query Filter 中,我只用了 SCOTT 的事務(wù),因為其曾用來(lái)執行過(guò)所有的 DML。在 Advanced Query 部分中,您可以輸入其他任何過(guò)濾器。填完所有的域后,單擊 Continue。 這將激活日志挖掘進(jìn)程對重做日志(在線(xiàn)的和存檔的,必要的話(huà))進(jìn)行搜索,尋找用戶(hù) SCOTT 發(fā)布的事務(wù)。進(jìn)程結束后,您將看到結果屏幕。 結果屏幕的頂端部分與下圖類(lèi)似: 結果表明,通過(guò)搜索找到兩個(gè)由 SCOTT 發(fā)布的事務(wù),這些事務(wù)影響了兩條記錄。 屏幕的底端部分顯示了這些事務(wù)的詳細信息。這是屏幕的局部視圖。您可以看到,事務(wù)顯示為 1 ins (表示“1 條插入語(yǔ)句”)。最左邊一欄顯示了事務(wù)標識符 (XID),是唯一標識事務(wù)的編號。 如果點(diǎn)擊事務(wù)標識符,您可以看到相應事務(wù)的詳細信息,如下圖所示: 如您所見(jiàn),您可以使用數據庫控制搜索和識別事務(wù)。單擊按鈕 Previous Transaction 和 Next Transaction 可以滾動(dòng)瀏覽通過(guò)搜索找到的所有事務(wù)。 使用案例 如何使用這一特性?有幾種方法。最重要的用途可能就是查清“誰(shuí)”做了“什么”。如果由于性能原因您沒(méi)有啟用審計,或者僅僅是沒(méi)有保留審計記錄,您只需通過(guò)挖掘重做日志(在線(xiàn)的和存檔的)在 LogMiner 界面中搜索相關(guān)線(xiàn)索即可。在搜索屏幕中,您可以在 Query Filter 下的 Advanced Query 域中輸入附加過(guò)濾條件。 假設,您要查找一個(gè)插入、刪除或更新了 RES_ID = 100002 的記錄的事務(wù)。您可以使用 dbms_logmnr 程序包中的 column_present 函數在重做流中搜索具體的值,如下所示: 這個(gè)函數將會(huì )提取 SCOTT 模式下 RES 表的 RES_ID 列中包含 100002 的所有事務(wù)。 您還可以使用該特性掘出針對該數據庫執行的 DDL 命令。要實(shí)現這一目的,選擇 Query Filter 部分中的單選按鈕 View DDL Only 即可。 收回選定的事務(wù) 在檢查一個(gè)事務(wù)時(shí),您想怎樣處理這個(gè)事務(wù)?一種想法是將其撤消,因為此事務(wù)的執行有誤,這或許是您查找該事務(wù)的首要原因。這非常簡(jiǎn)單。如果該事務(wù)是一個(gè)插入,您只需將其刪除即可;如果它是一個(gè)更新,則撤消會(huì )將該行還原至前一個(gè)值。 然而,請仔細觀(guān)察本例中使用的事務(wù)。第一個(gè)事務(wù)插入了一行。第二個(gè)事務(wù)更新了剛插入的行,而第三個(gè)事務(wù)將那一行刪除了。第一個(gè)事務(wù)(插入)就是您要收回的事務(wù)。但是,問(wèn)題是,那一行已經(jīng)被后續的事務(wù)刪除了,那么在本例中撤消事務(wù)是什么呢? 這就是 Oracle 數據庫 11g 中 Dependent Transaction 視圖特性的用途所在。單擊 Flashback Transaction。經(jīng)過(guò)一些搜索后,系統將顯示類(lèi)似下圖的屏幕: 該屏幕將為您顯示相關(guān)事務(wù)以及更新和刪除?,F在,在收回事務(wù)時(shí),您還可以收回其依賴(lài)項。 要實(shí)現這一目的,從下面的列表中選擇 Cascade 單選按鈕,然后單擊 OK 即可。 它會(huì )為您顯示所需收回的不同事務(wù)。單擊事務(wù) ID 查看 Oracle 將執行什么 SQL 語(yǔ)句來(lái)撤消這個(gè)事務(wù)。 例如,要撤消插入,Oracle 必須執行刪除,如上圖所示。如果點(diǎn)擊下一個(gè)事務(wù)(就在它的下面),您將看到收回下一個(gè)事務(wù)所需的詳細操作: 這樣,您就了解了操作構思。單擊 Submit,所有這些事務(wù)都將一次性全部回滾。這是撤消事務(wù)及其依賴(lài)項最徹底的方法。 命令行界面 如果您無(wú)權訪(fǎng)問(wèn)企業(yè)管理器怎么辦?或者也許您想通過(guò)腳本來(lái)完成這一切,那該怎么辦?程序包 DBMS_FLASHBACK(Oracle 數據庫 10g 中也提供該程序包)新增了一個(gè)名為 TRANSACTION_BACKOUT 的過(guò)程。這個(gè)過(guò)程超載,因此您必須將值傳遞給命名參數,如下所示。 declare trans_arr xid_array; begin trans_arr := xid_array('030003000D040000','F30003000D04010'); dbms_flashback.transaction_backout ( numtxns => 1, xids => trans_arr, options => dbms_flashback.cascade ); end; xid_array 類(lèi)型也是 Oracle 數據庫 11g 的新增內容。它用來(lái)向該過(guò)程傳遞一系列事務(wù)標識符。 LogMiner 的其他改進(jìn) 如果您一直使用 XML Type 作為數據類(lèi)型,那么在 Oracle 數據庫 11g 中您更有理由使用它,您會(huì )很高興地看到 LogMiner 也可以挖掘 XML 數據。XML 數據在 SQL_REDO 和 SQL_UNDO 列中都有顯示。 啟動(dòng) LogMiner 時(shí),您可以設置選項 SKIP_CORRUPTION,它會(huì )跳過(guò)重做日志中的受損塊。因此,即使部分數據損壞了,您也可以回收重做日志里的有效數據。 以下是這一改進(jìn)語(yǔ)法的用法: begin dbms_logmnr.start_logmnr( options => dbms_logmnr.skip_corruption ) ; end; 閃回數據存檔 Oracle9i 數據庫第 2 版以閃回查詢(xún)的形式引入了眾所周知的時(shí)間機器。閃回查詢(xún)允許您選擇更改前的數據。例如,如果您將一個(gè)值從 100 改為 200 并將其提交,即使更改已經(jīng)提交了,您仍然可以選擇兩分鐘前的值。這種技術(shù)使用了還原段中更改前的數據。在 Oracle 數據庫 10g 中,這項功能通過(guò)引入閃回版本查詢(xún)得到增強,您甚至可以將某一行的更改追溯到還原段所能提供的最久遠的更改狀態(tài)。 但是,這里存在一個(gè)小問(wèn)題:數據庫回收后,還原數據被清除了,隨之更改前的值也消失了。即使不回收數據庫,數據也可能因時(shí)間太長(cháng)而退出還原段為新更改讓出空間。 由于 11g 之前的閃回操作依賴(lài)于還原數據,而還原數據的可用時(shí)間短暫,您無(wú)法真正長(cháng)期使用這些數據或者將其用于審計之類(lèi)較永久的記錄。作為變通手段,我們通過(guò)編寫(xiě)觸發(fā)器來(lái)長(cháng)期記錄數據庫的更改。 不過(guò),不要感到失望。在 Oracle 數據庫 11g 中,閃回數據存檔結合了兩者的優(yōu)勢:它既提供閃回查詢(xún)的簡(jiǎn)易性與功能性,又不像還原數據一樣依賴(lài)臨時(shí)存儲。它在更加永久的位置(即閃回恢復區)記錄更改。 我們來(lái)看一個(gè)示例。(注:您需要激活自動(dòng)撤消管理,這樣閃回數據存檔才能發(fā)揮作用。)首先,創(chuàng )建一個(gè)閃回數據存檔,如下所示: SQL> create flashback archive near_term 2 tablespace far_near_term 3 retention 1 month 4 / Flashback archive created. 關(guān)于時(shí)間,先不用管術(shù)語(yǔ)“保留”的意義,我們稍后再討論。(這是記錄更改的位置。)存檔在表空間 far_near_term 中創(chuàng )建好了。 假設您需要記錄表 TRANS 的更改。那么,您只需啟用該表的閃回數據存檔狀態(tài),開(kāi)始在存檔中記錄更改即可。 SQL> alter table trans flashback archive near_term; Table altered. 這會(huì )將表置于閃回數據存檔模式?,F在,該表中的所有行更改都將受到永久跟蹤。我們來(lái)看一個(gè)演示。 首先,選擇該表的一個(gè)具體行。 SQL> select txn_amt from trans where trans_id = 2; TXN_AMT ---------- 19325.67 SQL> update trans set txn_amt = 2000 where trans_id = 2; 1 row updated. SQL> commit; Commit complete. 現在,如果您選擇了該行,則這一列將始終顯示 2000。要查找早先某一時(shí)間點(diǎn)時(shí)的值,您可以使用閃回查詢(xún),如下所示: elect txn_amt from trans as of timestamp to_timestamp ('07/18/2007 12:39:00','mm/dd/yyyy hh24:mi:ss') where trans_id = 2; TXN_AMT ---------- 19325.67 現在,隔一段時(shí)間,當還原數據從還原段中清除后,再次查詢(xún)這個(gè)閃回數據: select txn_amt from trans as of timestamp to_timestamp ('07/18/2007 12:39:00','mm/dd/yyyy hh24:mi:ss') where trans_id = 2; 結果返回:19325.67. 還原數據已經(jīng)清除了,那么這個(gè)數據來(lái)自何處呢? 我們問(wèn)問(wèn) Oracle。您可以使用自動(dòng)跟蹤來(lái)查看執行計劃: SQL> set autotrace traceonly explain SQL> select txn_amt 2 from trans 3 as of timestamp to_timestamp ('07/18/2007 12:39:00','mm/dd/yyyy hh24:mi:ss') 4 where trans_id = 2; Execution Plan ---------------------------------------------------------- Plan hash value: 535458644 ---------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop ------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 52 | 10 (10)| 00:00:01 | | | 1 | VIEW | | 2 | 52 | 10 (10)| 00:00:01 | | | 2 | UNION-ALL | | | | | | | |* 3 | FILTER | | | | | | | | 4 | PARTITION RANGE SINGLE| | 1 | 52 | 3 (0)| 00:00:01 | 1 | 1 |* 5 | TABLE ACCESS FULL | SYS_FBA_HIST_68909 | 1 | 52 | 3 (0)| 00:00:01 | 1 | 1 |* 6 | FILTER | | | | | | | |* 7 | HASH JOIN OUTER | | 1 | 4053 | 10 (10)| 00:00:01 | | |* 8 | TABLE ACCESS FULL | TRANS | 1 | 38 | 6 (0)| 00:00:01 | | | 9 | VIEW | | 2 | 8030 | 3 (0)| 00:00:01 | | |* 10 | TABLE ACCESS FULL | SYS_FBA_TCRV_68909 | 2 | 8056 | 3 (0)| 00:00:01 | | ------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - filter(NULL IS NOT NULL) 5 - filter("TRANS_ID"=2 AND "ENDSCN">161508784336056 AND "ENDSCN"<=1073451 AND ("STARTSCN" IS NULL OR "STARTSCN"<=161508784336056)) 6 - filter("F"."STARTSCN"<=161508784336056 OR "F"."STARTSCN" IS NULL) 7 - access("T".ROWID=("F"."RID"(+))) 8 - filter("T"."VERSIONS_STARTSCN" IS NULL AND "T"."TRANS_ID"=2) 10 - filter(("ENDSCN" IS NULL OR "ENDSCN">1073451) AND ("STARTSCN" IS NULL OR "STARTSCN"<1073451)) Note ----- - dynamic sampling used for this statement 該輸出回答了我們的疑問(wèn)“這個(gè)數據來(lái)自何處?”,數據來(lái)自表 SYS_FBA_HIST_68909,這是您先前為那個(gè)表定義的閃回存檔中的某個(gè)位置。您可以查看這個(gè)表,但是 Oracle 不支持在那里直接查看數據。不過(guò),我覺(jué)得您也沒(méi)有必要那樣做。 存檔中的數據能保留多長(cháng)時(shí)間呢?這就是保留期限的作用了。數據可以在該期限內一直保留。保留期限過(guò)后,當有新的數據進(jìn)來(lái)時(shí),較老的數據將被清除。您也可以自己清除數據,例如: alter flashback archive near_term purge before scn 1234567; 管理閃回存檔 您可以在一個(gè)存檔中添加多個(gè)表空間。反過(guò)來(lái),您也可以從一個(gè)存檔中刪除表空間。如果您打算使用已經(jīng)具有其他用戶(hù)數據的表空間,則存在閃存數據存檔數據將表空間擠滿(mǎn)的風(fēng)險,從而沒(méi)有空間供用戶(hù)數據使用。為了降低這種風(fēng)險,您可以設置存檔在表空間內可以占用的空間定額。您可以通過(guò)以下語(yǔ)句設置定額: alter flashback archive near_term modify tablespace far_near_term quota 10M; 您可以通過(guò)查詢(xún)字典視圖查看哪些表開(kāi)啟了閃回數據存檔: SQL> select * from user_flashback_archived_tables; TABLE_NAME OWNER_NAME ------------------------------ ------------------ FLASHBACK_ARCHIVE_NAME ------------------------------------------------- TRANS ARUP NEAR_TERM 您可以通過(guò)查詢(xún)字典視圖查找存檔: sql> select * from flashback_archives; FLASHBACK_ARCHI FLASHBACK_ARCHIVE# RETENTION_IN_DAYS PURGE_SCN STATUS --------------- ------------------ ----------------- ---------- ------- NEAR_TERM 1 30 1042653 MED_TERM 2 365 1042744 LONG_TERM 3 1825 1042838 使用多個(gè)存檔可以使您在不同情況下通過(guò)獨創(chuàng )方式對其進(jìn)行應用。例如,某酒店企業(yè)的數據庫可能需要保留一年的預定信息,而需要保留三年的付款信息。那么,您可以定義多個(gè)帶有不同保留策略的存檔,然后將其分配給各個(gè)表?;蛘?,如果有統一的保留策略,您可以只定義一個(gè)存檔并將其設為默認選項。 alter flashback archive near_term set default; 當某個(gè)表不需要存檔時(shí),您可以通過(guò)以下命令將存檔關(guān)閉: alter table trans no flashback archive; 如您所見(jiàn),您一行代碼都不需要編寫(xiě)就實(shí)現了一個(gè)功能強大的更改記錄系統。 與常規審計的區別 閃回數據存檔與常規審計的區別是什么?首先,后者需要將 audit_trail 參數設置為 DB 或 DB_EXTENDED,并將審計線(xiàn)索寫(xiě)入 SYSTEM 表空間的 AUD$ 表中。閃回數據存檔可在任何表空間上(或多個(gè)表空間上,甚至存儲用戶(hù)數據的表空間的某些部分上)進(jìn)行定義,因此可以在更廉價(jià)的存儲設備上進(jìn)行定義。 其次,審計以自主事務(wù)為基礎,會(huì )造成一些性能開(kāi)銷(xiāo)。閃回數據存檔由專(zhuān)用后臺進(jìn)程 FBDA 編寫(xiě),因此對性能的影響較小。 最后,閃回數據存檔可定期自動(dòng)清除。審計線(xiàn)索必須通過(guò)人工進(jìn)行維護。 使用案例 閃回數據存檔具有多種便捷的用途。這里給出部分用途: - 審計以記錄數據的更改方式
- 支持應用程序撤消更改(糾正錯誤)
- 調試數據的更改方式
- 遵守某些規定,不準數據在某段時(shí)間內出現更改。閃回數據存檔不屬于常規表,所以普通用戶(hù)無(wú)法對其進(jìn)行更改操作。
- 可在更廉價(jià)的存儲設備上記錄審計線(xiàn)索,因而能以較低的成本保留更多的信息。
結論 錯誤發(fā)生了,但是現在您可以自信地斷定,您能夠識別引起錯誤的具體更改,而且您擁有通過(guò)事務(wù)收回完全回滾這些錯誤的工具。但是,您的方法不再局限于從存檔的和在線(xiàn)的重做日志中挖掘更改,更改已經(jīng)永久地記錄在了閃回存檔中?,F在,只需通過(guò)幾個(gè)命令就可以針對任何實(shí)際目的在閃回恢復區審計更改了。 返回到“Oracle 數據庫 11g:面向 DBA 和開(kāi)發(fā)人員的重要特性”主頁(yè) Arup Nanda (arup@proligence.com) 是 Starwood Hotels and Resorts 的數據庫系統經(jīng)理,從事 Oracle 的 DBA 職業(yè)十多年,并且在 2003 年由《Oracle 雜志》 評選為“年度 DBA”。Arup 經(jīng)常在 Oracle 相關(guān)活動(dòng)中發(fā)表演講,并在 Oracle 相關(guān)雜志上撰寫(xiě)文章,他是紐約 Oracle 用戶(hù)群執行委員會(huì )的成員,并且是一位 Oracle ACE。他與其他人合作編寫(xiě)了《Oracle 隱私安全性審計》(Rampant TechPress 出版)一書(shū)。 |