這篇文章源於在PL/SQL領域很是有建樹的專家:Steven Feuerstein 的推薦。web
因而突發奇想,將該篇文章翻譯成了中文。若是經過個人努力,確實讓一些朋友有所收穫,我將很是榮幸。sql
文章開始:數據庫
以前個人一些文章中,曾經建議經過使用11g中提供的FLASHBACK的數據歸檔功能而直接替換日誌信息表(journalling tables)。即咱們已經再也不須要針對某些專門表中的記錄,咱們須要持續跟蹤記錄全部的改變和被改變以前的記錄狀態(能夠參考以下連接 http://technology.amis.nl/blog/2453/oracle-11g-total-recall-flashback-in-the-hands-of-database-designers-and-application-developers-at-last-and-the-end-of-journalling-tables)。經過Flashbck的數據歸檔功能不但能夠減小編程工做,並且經過該功能能夠大幅提高DML操做的性能,同時又可得到許多的方便的功能。例如:Flashback Queries能夠直接地象SQL查詢同樣查詢歷史數據,甚至經過使用dbms_flashback包,咱們可使用相同的應用程序和相同的查詢操做去檢索過去某個時間點的數據。編程
在以前的不太長的時間,Flashback有許多功能上的限制,而使得其基本上不能記錄那些已經存有歷史數據但結構又發生變化的表。隨着11GR2在這些方面做的改進,絕大多數的限制都已經取消了,而且象增長、重命名以及刪除字段和限制這樣的對於表的DDL操做以已經能夠實現。session
另一個致使日誌表能夠消失的緣由,就是經過Flashback的Flashback Queries操做,能夠獲得一些重要的附加信息。什麼時候(DML操做的時間戳)和操做信息(操做類型和原數據信息),這些信息能夠很好的知道,操做者到底致使了怎樣的變化。而這些在一個部門內的監管是很是重要的。過去,習慣使用數據庫用戶就是真實用戶去提交交易。可是當今業界使用多層服務組件和WEB應用經過池化鏈接數據庫,而形成數據庫用戶每每不是操做的真實用戶。對於最終用戶的操做一般(或者應該這樣)經過sys_context(‘userenv’, ‘client_identifier’)能夠得到,經過設置dbms_session.set_identifier() 或者直接使用鏈接(例如:JDBC)。對於咱們的日誌而言,咱們須要記錄或篩選真實的執行人和客戶身份。oracle
這篇文章描述了記錄和後督交易時客戶身份信息的方法。app
象其餘一些人同樣,我也不得不使用,我不甚熟悉的ORACLE數據庫自帶的審計功能。但讓使用不夠深刻。可是,當試圖檢查過去某些數據庫交易信息的時候,老是可以天然的想到使用使用審計功能。而且這種方法確實讓我獲得了我須要的信息:每一個交易的操做記錄,而且經過交易號(transactionid)能夠關聯到閃回的歷史數據查詢。這些數據會包含用戶身份和執行的全部操做。Oralce數據庫的審計能夠進行許多種不一樣操做。從每種對象類型的創建、受權更新和執行操做,到每一個數據庫用戶執行的操做甚至非法的對象。可是由於審計會產生大量的記錄數據,而導致咱們不得不按期清理這些歷史數據。一般這些週期只能都是很是短暫的。爲了記錄交易歷史,我嘗試經過日誌錶轉而使用審計功能。而且我須要肯定審計的等級--那些操做和那些對象(是否還包含用戶?)如今,我須要使用FLASHBAKC功能協助,就像我參考的那些文檔,而且我須要確保每一個針對EMP表的DML操做都必須被記錄。這就意味着,下面的SQL開啓審計功能: ide
- AUDIT INSERT, UPDATE, DELETE ON SCOTT.EMP
爲了審計功能,我假設一個web應用,這個應用可讓真是的最終用戶修改數據。在數據庫中執行以下操做:設置用戶身份,應用程序須要執行: 工具
- begin
- dbms_session.set_identifier('TheRealUser');
- end;
進行下一個DML操做:性能
- update emp
- set sal = sal + 100
- where job ='CLERK'
當交易被提交後,EMP使用了新的值,而原有的值成爲了歷史數據。這些歷史數據,能夠經過Flashback Versions Query被咱們查詢。
- select ename
- , sal
- , versions_xid
- , VERSIONS_STARTTIME
- , VERSIONS_ENDTIME
- from emp VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE
- where job = 'CLERK'
結果集以下:
- ENAME SAL VERSIONS_XID VERSIONS_STARTTIME VERSIONS_ENDTIME
- ---------- ------ ---------------- ------------------------- -------------------------
- ADAMS 1405 07001E00A9040000 06-FEB-11 08.12.09.00 AM 06-FEB-11 08.42.13.00 AM
- ADAMS 1505 04000E0088040000 06-FEB-11 08.42.13.00 AM
- ADAMS 1400 06-FEB-11 08.12.09.00 AM
- JAMES 1255 07001E00A9040000 06-FEB-11 08.12.09.00 AM 06-FEB-11 08.42.13.00 AM
- JAMES 1355 04000E0088040000 06-FEB-11 08.42.13.00 AM
- JAMES 1250 06-FEB-11 08.12.09.00 AM
- MILLER 1605 07001E00A9040000 06-FEB-11 08.12.09.00 AM 06-FEB-11 08.42.13.00 AM
- MILLER 1705 04000E0088040000 06-FEB-11 08.42.13.00 AM
- MILLER 1600 06-FEB-11 08.12.09.00 AM
- SMITH 1105 07001E00A9040000 06-FEB-11 08.12.09.00 AM 06-FEB-11 08.42.13.00 AM
- SMITH 1205 04000E0088040000 06-FEB-11 08.42.13.00 AM
- SMITH 1100 06-FEB-11 08.12.09.00 AM
很顯然,這些記錄的數據中沒有修改數據人的信息。可是,配合以前開啓的審計追蹤功能,我能夠關聯Flashback的Versions Query與 USER_OBJECT_AUDIT試圖,找到更多的執行人(WHO)的數據信息:
- select ename
- , sal
- , uat.client_id
- , uat.os_username
- , uat.userhost
- , uat.username
- , uat.scn
- , versions_xid
- , VERSIONS_STARTTIME
- , VERSIONS_STARTSCN
- , VERSIONS_ENDTIME
- , VERSIONS_ENDSCN
- from emp VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE eh
- join
- user_audit_trail uat
- on ( eh.versions_xid = uat.transactionid)
- where job = 'CLERK'
- order
- by ename, versions_starttime
結果集顯示客戶身份(client identifier)信息與實際的操做用戶不符。
- ENAME SAL CLIENT_ID OS_USERNAME USERHOST USERNAME SCN VERSIONS_XID VERSIONS_STARTTIME VERSIONS_STARTSCN
- ---------- ---------------------- ---------------------------------------------------------------- ------------------------
- ADAMS 1505 TheRealUser demo xp-vm SCOTT 2200769 04000E0088040000 06-FEB-11 08.42.13.00 AM 2200778
- JAMES 1355 TheRealUser demo xp-vm SCOTT 2200769 04000E0088040000 06-FEB-11 08.42.13.00 AM 2200778
- MILLER 1705 TheRealUser demo xp-vm SCOTT 2200769 04000E0088040000 06-FEB-11 08.42.13.00 AM 2200778
- SMITH 1205 TheRealUser demo xp-vm SCOTT 2200769 04000E0088040000 06-FEB-11 08.42.13.00 AM 2200778
注意:若是我想經過flash的versions query找到開啓審計以前的歷史數據,須要使用左外聯接在咱們的查詢中。
- select ename
- , sal
- , uat.client_id
- , uat.os_username
- , uat.userhost
- , uat.username
- , uat.scn
- , versions_xid
- , VERSIONS_STARTTIME
- , VERSIONS_STARTSCN
- , VERSIONS_ENDTIME
- , VERSIONS_ENDSCN
- from emp VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE eh
- left outer join
- ( select uat.*
- , row_number() over (partition by transactionid order by extended_timestamp) rn
- from user_audit_trail uat
- ) uat
- on ( eh.versions_xid = uat.transactionid)
- where job = 'CLERK'
- and rn = 1
- order
- by ename, versions_starttime
如今,我已經介紹了一個嵌套SQL,如何經過一個查詢將user_audit_trail全部交易都查詢出來,而不是經過一個交易一個查詢的方式進行檢索。
這個方法確實很是簡單。由於,咱們能夠象輕鬆開啓審計信息那樣開啓每張表的Flashback功能。
可是這裏卻有一個審計開銷缺點。首先是性能問題,由於對於每條被「觸碰」到的記錄,都會觸發日誌信息記錄,同時存儲在系統審計表SYS.AUD$中的數據量將是很是驚人的。由於審計將會收集全部用戶和對象的操做。審計信息存儲表須要週期性清除。注意,清理能夠有選擇行的指定某個對象或者操做。
爲了簡化標準的審計跟蹤功能,咱們能夠構建一個JOB,週期性地從 sys.aud$表中抽取咱們須要的記錄信息,並構建本身須要的交易歷史。由於審計機制會完整的記錄每一個交易的DML操做語句但咱們只是須要每一個交易的單個記錄,咱們能夠經過整合針對每一個交易記錄的審計信息,達到大幅下降交易歷史數據量的目的。交易歷史表能夠象以下:
- create table transaction_history
- ( transaction_id varchar2(100) not null
- , client_identifier varchar2(200)
- , os_user varchar2(200)
- , scn number
- , transaction_start_timestamp timestamp default systimestamp
- , db_user varchar2(100)
- , application_info varchar2(2000)
- )
從審計跟蹤表中抽取交易歷史數據操做:
- insert into transaction_history
- ( transaction_id
- , client_identifier
- , os_user
- , scn
- , transaction_start_timestamp
- , db_user
- )
- select uat.transactionid
- , uat.client_id
- , uat.os_username
- , uat.scn
- , uat.extended_timestamp
- , uat.username
- from ( select uat.*
- , row_number() over (partition by transactionid order by extended_timestamp) rn
- from user_audit_trail uat
- ) uat
- where rn = 1
- and transactionid is not null
對於審計跟蹤(可能須要部分清理)和交易歷史表(可能不能所有更新),咱們能夠將二者結合來構建基於EMP表的交易歷史記錄。
- select ename
- , sal
- , versions_xid
- , nvl(th.client_identifier, uat.client_id) client_id
- , nvl(th.os_user, uat.os_username) os_user
- , uat.userhost userhost
- , nvl(th.db_user, uat.username) db_user
- , nvl(th.scn,uat.scn) scn
- , VERSIONS_STARTTIME
- , VERSIONS_STARTSCN
- , VERSIONS_ENDTIME
- , VERSIONS_ENDSCN
- from emp VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE eh
- left outer join
- ( select uat.*
- , row_number() over (partition by transactionid order by extended_timestamp) rn
- from user_audit_trail uat
- ) uat
- on ( eh.versions_xid = uat.transactionid)
- left outer join
- transaction_history th
- on ( eh.versions_xid = th.transaction_id)
- where job = 'CLERK'
- and uat.rn = 1
- order
- by ename, versions_starttime
注意:查詢能夠部分的結合審計跟蹤信息和咱們本身的交易歷史表在一個試圖中。
上面說起的大概方法給咱們提供一個針對標準應用構建日誌表的思路。在這個舉例中,咱們並無創建觸發器。簡單地開啓針對某些表DML操做的審計跟蹤,配以這些表的flashback歸檔數據,就足以構建咱們的日誌信息。在後續的文章中將會更爲詳細的介紹。
固然,若是咱們要實際構建這樣的日誌信息也許還有一個難點須要克服,即關於DBA的審計,尤爲是對於標準審計特性,對於DBA和對於應用開發人員的日誌記錄,咱們的應用每每是沒有考慮的(可是,咱們須要他或她也去創建flashback的歸檔數據)。
在將來的文章中,我將會討論看似類似的問題:跟蹤交易歷史的方法和經過flashback歸檔數據收集全面的日誌信息。
----EOF 譯文完。
原文連接:
Thanks Lucas Jellema -:)