1. 程式人生 > 其它 >database replay基礎學習(r4筆記第90天)

database replay基礎學習(r4筆記第90天)

在11g中,database replay是一個很重要的新特性,按照這個特性的說法,可以完整地捕獲資料庫的負載資訊,便於在需要的時候隨時重放。 使用這種方法,可以以二進位制檔案格式捕獲 SQL 級以下的所有資料庫活動,然後在同一資料庫或不同資料庫內進行重放。 基本的流程圖如下:

自己看到這個特性也是很感興趣,然後在測試環境進行了多次測試,可能我學習的方式比較較真,對於很多知識點,都是希望先能簡單模擬,弄出個結果,然後自己才喜歡搗鼓一些細節的內容。 越是這樣做,似乎對於這個特性還是有很多的細節需要注意,總是碰到各種各樣的問題,最後都是不了了之。在很多網站,帖子中也搜了不少的相關文件,但是描述的比較全的帖子還是比較少。特意整理了一下,自己也反覆做了測試,基本能夠保證按照步驟順利完成。 首先我們需要建立一個目錄,然後賦予許可權。

create table n1.test(id number);
SQL> create directory dbplay as 'c:testdbreplay'    ;                    
Directory created.                                                              
 
SQL> grant read,write on directory dbplay to n1;                                                                                                                
Grant succeeded. 

然後使用dbms_workload_capture來準備開始捕獲資料庫層面的負載情況,在這個例子中我們指定時長為600秒,也可以中途終止。也可以指定對於某個schema進行細粒度的捕獲。 BEGIN DBMS_WORKLOAD_CAPTURE.START_CAPTURE ( name => 'dbreplay_test', dir => 'dbplay', duration => 600); END; / 這個時候我們會碰到錯誤。 ERROR at line 1: ORA-20222: Invalid DB State or Input. Input "dbplay" is not a valid DIRECTORY object!

這個問題算比較清晰的,就是目錄名的問題,只需要改為大寫即可。 如果碰到如下的錯誤。 ERROR at line 1: ORA-15505: cannot start workload capture because instance 1 encountered errors while accessing directory "c:testdbreplay" 說明在指定的捕獲目錄下,很可能有之前捕獲的檔案,會有一定的衝突。可以清空或者換一個目錄。 開始捕獲

BEGIN DBMS_WORKLOAD_CAPTURE.START_CAPTURE ( name => 'dbreplay_test', dir => 'DBPLAY', duration => 600); END; / 這個時候檢視目錄中的檔案,就會發現生成了幾個資料夾,和一個.start的檔案(檔案為空),這也就標誌著捕獲開始了。 03/29/2015 09:48 PM <DIR> .. 03/29/2015 09:48 PM <DIR> cap 03/29/2015 09:47 PM <DIR> capfiles 03/29/2015 09:47 PM <DIR> wcr_cap_0000f.start 在捕獲期間,我們嘗試執行下面的一個指令碼,來進行大量的資料插入,這個語句會進行大量的硬解析,存在一定的效能隱患。 begin for x in 1..200000 loop insert into n1.test values(x); commit; end loop; end; / 如果時間在600秒內,完成後就會自動結束,我們也可以在中途進行手動結束捕獲。 BEGIN DBMS_WORKLOAD_CAPTURE.FINISH_CAPTURE(); END; / 技術捕獲後,就會發現.start檔案就會自動清除。 我們可以使用如下的指令碼來進行捕獲情況的監控。 select id,name,status,capture_size from DBA_WORKLOAD_CAPTURES; 最後我們使用如下的方法來進行檔案的預處理,處理之後就會生成一個pp開頭的目錄,我的資料庫版本是11.2的,檔案就為: pp11.2.0.1.0 BEGIN DBMS_WORKLOAD_REPLAY.PROCESS_CAPTURE ( capture_dir => 'DBPLAY'); END; / 這個時候,捕獲工作就完成了。 如果在工作中,我們可以在測試環境中進行這些資訊的重放。這個時候就需要把捕獲目錄中的檔案都拷貝到測試機器上。 當然為了演示方便,也可以在當前的環境進行重放。 在測試機器上,我們需要建立對應的目錄,把捕獲檔案都拷貝過來。 SQL> create or replace directory target_replay as 'c:testtarget_replay'; Directory created. SQL> grant read,write on directory target_replay to n1; Grant succeeded. 這個時候我們需要清空表中的資料,這樣就能夠很 清楚的看到重放的過程中資料的變化。 truncate table n1.test; 開始進行初始化 BEGIN DBMS_WORKLOAD_REPLAY.INITIALIZE_REPLAY ( replay_name => 'target_replay_test', replay_dir => 'TARGET_REPLAY'); END; / BEGIN DBMS_WORKLOAD_REPLAY.PREPARE_REPLAY (synchronization => TRUE); END; / 這個時候檢視目錄結構,會發現又多了一個目錄rep開頭的,這個是replay初始化的時候生成的。 Directory of C:testtarget_replay 03/29/2015 09:14 PM <DIR> cap 03/29/2015 09:14 PM <DIR> capfiles 03/29/2015 09:14 PM <DIR> pp11.2.0.1.0 03/29/2015 09:16 PM <DIR> rep438010913 這個時候我們可以通過wrc來開啟重放客戶端,在另外一個視窗中執行即可。 C:testtarget_replay>wrc system/oracle mode=replay replaydir=c:testtarget_replay Workload Replay Client: Release 11.2.0.1.0 - Production on Sun Mar 29 21:18:20 2 Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved. Wait for the replay to start (21:18:20) 可以看到客戶端中已經開始等待重放了。 不用著急,我們在另外一個視窗中開始重放。 BEGIN DBMS_WORKLOAD_REPLAY.START_REPLAY (); END; / 這個時候不間斷的檢視test表中的資料,就會發現資料在一點一點的插入。如果存在效能問題,也可以有針對性的分析。 SQL> select count(*)from n1.test; COUNT(*) ---------- 91458 SQL> / COUNT(*) ---------- 159206 SQL> / COUNT(*) ---------- 175586 SQL> / COUNT(*) ---------- 200000 我們可以最後指定重放完畢。客戶端中就會觸發退出。 BEGIN DBMS_WORKLOAD_REPLAY.CANCEL_REPLAY (); END; / Wait for the replay to start (21:18:20) Replay started (21:19:16) Replay finished (21:21:11) 我們可以通過如下的語句來監控重放的情況 select id,name,status,user_calls from DBA_WORKLOAD_REPLAYS; 如果我們想得到捕獲過程中的報告,可以使用如下的方式完成。 set long 100000; set pagesize 40000; select dbms_workload_replay.report(2,'TEXT') from dual; 最後就是這些資訊的清理,如果已經完成了重放,分析完成了,就可以刪除這些捕獲或者重放的配置資訊。傳入的引數就是對應的id,在DBA_WORKLOAD_CAPTURES,DBA_WORKLOAD_REPLAYS中可以得到對應的id exec dbms_workload_replay.DELETE_REPLAY_INFO(1); exec dbms_workload_capture.DELETE_CAPTURE_INFO(1);