記一次資料同步需求的改進(二)

jeanron100發表於2015-10-31
在之前寫過 記一次資料同步需求的改進(一)之後,就開始著手對這個需求進行實踐。
所謂實踐出真知,在實際做的時候才發現可能計劃的再好,做的時候還真不是那麼回事。
在之前的郵件中已經確認目標庫是一個統計分析庫,首先拿到這個環境,先調查一番,發現了一個奇怪的現象。
檢視這個庫的歸檔情況的時候發現這個庫每天的凌晨開始要切換20多次日誌。
Redo Switch times per hour                                              STATDB1                     2015-Oct-28 11:37:52
MON DA   00   01   02   03   04   05   06   07   08   09   10   11   12   13   14   15   16   17   18   19   20   21   22   23
--- -- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
10  25   27    0    0    0    0    0    0    1    0    0    0    0    0    0    0    0    1    0    0    0    0    0    0    0
10  26   25    0    0    0    0    0    0    1    1    0    0    0    0    0    0    0    1    0    0    0    0    0    0    0
10  27   27    1    0    0    0    0    0    1    0    0    0    0    0    0    0    0    0    0    0    0    0    1    0    0
10  28   27    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0
可以抓取近幾天的歸檔情況的圖表來進一步驗證,每天都會如此。可以看到在特定的時間內確實都發生一些額外的資源消耗,這是非常奇怪的。

檢視DB time的情況,發現在零點的時候也會出現一個大的抖動,這個是需要格外注意的。

出於謹慎起見,準備先來分析一個這個問題,沒想到這個問題對目前的這個需求來說意義重大,也算歪打正著。
首先檢視了在問題時間段sql的DB time使用情況
   SNAP_ID SQL_ID        EXECUTIONS_DELTA ELAPSED_TI PER_TOTAL
---------- ------------- ---------------- ---------- ----------
     37828 4yf9vjwa2yg5j               14 1433s      35%
     37828 20v7cntjrscg7                1 725s       18%
     37828 6yxdqb7mj3jys             5966 632s       15%
     37828 d0hhst2fhvmsb               18 383s       9%
     37828 1n3gxw12c2pap               12 99s        2%
然後逐個分析sql,發現sql_id 20v7cntjrscg7對應的sql竟然是一個job,每天都會嘗試全量同步一次資料,當然這個代價還是很高的
$ sh showsqltext.sh 20v7cntjrscg7
DECLARE job BINARY_INTEGER := :job;  next_date TIMESTAMP WITH TIME ZONE := :mydate;  broken BOOLEAN := FALSE;  job_name VARCHAR2(30) := :job_name;  jo
b_subname VARCHAR2(30) := :job_subname;  job_owner VARCHAR2(30) := :job_owner;  job_start TIMESTAMP WITH TIME ZONE := :job_start;  job_scheduled_start
 TIMESTAMP WITH TIME ZONE := :job_scheduled_start;  window_start TIMESTAMP WITH TIME ZONE := :window_start;  window_end TIMESTAMP WITH TIME ZONE := :w
indow_end;  chain_id VARCHAR2(14) :=  :chainid;  credential_owner varchar2(30) := :credown;  credential_name  varchar2(30) := :crednam;  destination_o
wner varchar2(30) := :destown;  destination_name varchar2(30) := :destnam;  job_dest_id varchar2(14) := :jdestid;  log_id number := :log_id;  BEGIN  d
eclare
 v_owner  varchar2(30);
begin
execute immediate 'truncate table accstat.TEST_PROTECT_LOG';
v_owner :='ACC00';
accstat.LOAD_TEST_PROTECT_LOG(v_owner);
commit;
dbms_session.close_database_link(v_owner);
v_owner :='ACC02';
accstat.LOAD_TEST_PROTECT_LOG(v_owner);
commit;
。。。
  :mydate := next_date; IF broken THEN :b := 1; ELSE :b := 0; END IF; END;     
這個過程首先是truncate表然後開始透過db link來從各個源端來同步資料到這個表中,至於重新整理細節是在一個儲存過程LOAD_TEST_PROTECT_LOG中做的,其實所做的工作就是insert的方式,只是使用了bulk collect,和insert all等方式進行了包裝和改進,所以每天都在默默的進行一次全量的同步,當然如果是一個簡單的效能問題也就罷了,關鍵是開發需要我同步的其中一張表就是這個job中正在同步的表,所以我產生了一些問題。
經過和開發的同事溝通,他們對這個部分目前沒有使用需求,和同事聊了聊,他們說印象中這種同步都是已經禁掉了,但是看來還是存在一個漏網之魚,每天都在默默的進行著同步,而且沒有使用到,想想就覺得悲涼。
所以發現了這個問題之後,開始重新審視這個需求,首先這個表是一個歷史記錄表,對於開發來說只需要去讀取即可。然後他們需要的是增量資料,每天進行一次同步,如果按照這個需求,目前的job所做的工具已經滿足了,可以直接告訴開發需求已經滿足了即可,但是我DBA的角度來說,這個實現方式讓人感覺還是太過於浪費,每天都需要全量同步一次資料,而且資料量也不小,每天同步勢必浪費了不少的資源。而且還有一個難點比較困擾我,就是源端存在10多個使用者表,如果根據之前的需求時間欄位來抽取資料,還是需要建立索引,所以這樣還需要在源端逐個建立索引,這個工作量也比較大,而且對於線上關鍵業務影響也很大。
那麼增量資料的同步還有什麼好的辦法嗎,物化檢視的增量重新整理就是一個很好的解決方案,我們只需要在源端建立物化檢視日誌即可,然後在目標端建立物化檢視,每次重新整理都採用增量的重新整理模式。這種增量和原來需求中的欄位抽取方式是完全吻合的。
對於這一點,和開發同事進行了溝通,他們非常贊同,因為不需要建立索引,而且重新整理的流程似乎更加簡單了,對於他們來說也不需要做更多的評估工作了。其實對於DBA來說也是如此。
按照這種思路實現方式就會發生改變,原來的實現方式是這樣的。

改進之後,需要建立一些物化檢視來做增量重新整理,方式就是下面的樣子。

對於這種方式。實現方式如下,具體實現的時候也碰到了一些問題。
首先需要在源端建立物化檢視日誌,
> create materialized view log on acc00.test_protect_log;
Materialized view log created.
然後在目標端開始建立物化檢視。但是奇怪的是竟然報錯了。
SQL> create materialized view acc00_test_protect_log refresh fast as select * from ACC00.test_protect_log@ACC00;
create materialized view acc00_test_protect_log refresh fast as select * from ACC00.test_protect_log@ACC00
*
ERROR at line 1:
ORA-12018: following error encountered during code generation for
"ACCSTAT"."ACC00_TEST_PROTECT_LOG"
ORA-00942: table or view does not exist
Elapsed: 00:04:52.41
經過分析排查發現,db link基於的是一個源端的只讀使用者,沒有物化檢視日誌的訪問許可權,所以簡單修復即可。
在統計庫中再次建立就沒有問題了。
SQL> create materialized view acc00_test_protect_log refresh fast as select * from ACC00.test_protect_log@ACC00;
Materialized view created.
Elapsed: 00:04:41.86
然後再次嘗試重新整理就很快了,因為是增量的方式,而且資料量相對要少很多。
SQL> exec dbms_mview.refresh('acc00_test_protect_log','F');
PL/SQL procedure successfully completed.
對於其它的源端使用者表也進行了類似的操作,最開始的全量重新整理還是會消耗一些額外的資源,但是以後就不會有這樣的問題了。
最後一個問題就是對於開發人員來說,如何透明的顯示為一個test_protect_log,可以直接使用檢視來完成,因為開發只需要讀取,不需要修改。
create or replace view accstat.test_protect_Log as
select * from ACCSTAT.ACC00_TEST_PROTECTLOG  
union all
select * from ACCSTAT.ACC02_TEST_PROTECT_LOG
union all
。。。
當然工作做完了,重新整理的過程還是很快的,基本十多秒回全部重新整理完成。
最後來看看改進只有的歸檔情況,藍色框中再也沒有這種抖動了。


所以問題處理還是要謹慎,細心,考慮全面,多溝通,就去能有預期的改進。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-1819981/,如需轉載,請註明出處,否則將追究法律責任。

相關文章