天天看點

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

所謂實踐出真知,在實際做的時候才發現可能計劃的再好,做的時候還真不是那麼回事。

在之前的郵件中已經确認目标庫是一個統計分析庫,首先拿到這個環境,先調查一番,發現了一個奇怪的現象。

檢視這個庫的歸檔情況的時候發現這個庫每天的淩晨開始要切換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';

。。。

  :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基于的是一個源端的隻讀使用者,沒有物化視圖日志的通路權限,是以簡單修複即可。

在統計庫中再次建立就沒有問題了。

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

當然工作做完了,重新整理的過程還是很快的,基本十多秒回全部重新整理完成。

最後來看看改進隻有的歸檔情況,藍色框中再也沒有這種抖動了。

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

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