記一次資料同步需求的改進(二) (r7筆記第5天)
在之前寫過記一次資料同步需求的改進(一) (r7筆記第2天)之後,就開始著手對這個需求進行實踐。
所謂實踐出真知,在實際做的時候才發現可能計劃的再好,做的時候還真不是那麼回事。
在之前的郵件中已經確認目標庫是一個統計分析庫,首先拿到這個環境,先調查一番,發現了一個奇怪的現象。
檢視這個庫的歸檔情況的時候發現這個庫每天的凌晨開始要切換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
。。。
當然工作做完了,重新整理的過程還是很快的,基本十多秒回全部重新整理完成。
最後來看看改進只有的歸檔情況,藍色框中再也沒有這種抖動了。
所以問題處理還是要謹慎,細心,考慮全面,多溝通,就去能有預期的改進。