整個系統可以從功能上分為3塊:
當一天結束後,各個業務系統產生了大量的數據,這些數據由定時任務進行加工、抽取到數據倉庫存儲,當半夜你還在睡覺的時候,這些定時任務就在默默的運行著。
而每天加工的數據通常要求在上班工作時間之前加工完成,然後通過數據智能平臺的查詢系統供業務系統查詢調用,這一次數據沒有查詢到是因為在第二天早上10點,數據還沒有加工完成。下面就是找問題優化了,因為正常來講,即使定時任務鏈再長,也不會慢到第二天10點鐘數據還沒有出來。下面就是找問題,然後進行優化了。
通過任務日志發現有一個上遊系統的數據抽取執行時間有3個小時,而數據量僅100萬。當然,光憑這樣還無法確定這個任務是否是可以被優化的。
查看任務代碼,邏輯還比較簡單:有一張原始數據錶,記錄商品信息以及定義的分類(這一點是虛構的,實際情况要複雜一些,我這裏精簡然後轉換了一下,便於理解),而數倉的目標錶是將分類和商品分別存儲在不同的錶中,大致結構如下。
那為什麼需要進行這樣的轉換呢? 這是因為整個大的系統,一般來說只能定義一些基本的規範,而具體的細節規範則無法約束,比如A系統的身份證字段名稱為card_no,而B系統的身份證字段名稱為crdt_no(這種情况大家應該經常遇到);再比如處理實體關系的時候,處理方式也是不同的,1對1的關系,可以建兩張錶關聯,也可以一張錶都存儲,這就造成了多個系統的不統一性,而這種情况是不可避免的,因為從業務系統來說,都保證了系統的正常運行。
而數倉對多個原始數據處理的時候就需要考慮到兼容的問題,所以就會出現如上圖的轉換過程。
而這個任務執行3個小時的原因在於原始錶中的一條記錄,會轉換到數倉錶中的三張錶中,而且這三張錶是通過id進行關聯,整個代碼流程如下。
然而問題來了,100萬的數據,跑了3個小時,然後我開始嘗試去優化程序的執行流程,大概從一下幾點入手
經過優化,效率有一些提昇,但並不是很明顯(有同學可能要問了,這些都是很基本的,為什麼最開始做? 咳咳。。。這個嘛,曆史原因吧,在最開始數據可能不多,不論以什麼方式執行,都差別不大,比如執行10分鐘和執行20分鐘,看似2倍的執行效率,但是由於沒有影響到業務系統,且一直正常運行,也就沒有看出問題)。
這裏數據是需要關聯的,所以我們是需要插入數據並拿到這條記錄的自增長id,然後插入到關聯錶,而錶結構基本不可能去動的(錶結構動了那真是牽一發而動全身了,第二天准得被叫去喝茶)。
那麼我們先來分析一下這裏為什麼執行這麼慢呢。
首先想到的就是批量插入,批量插入可以有效的降低數據庫訪問次數。但是這裏不能進行批量插入是因為需要取到自增長id,感覺陷入了困境。
當天晚上昨晚運動之後,拋開煩惱,覺得渾身舒坦。
突然,腦袋靈光一閃,數據庫的自增長id是由數據庫控制的數值,而自增長的步長我們是知道的,比如自增長步長為1,當前自增長id為1的話,那麼可以肯定,下一條記錄的自增長id就為2,以此類推。
那是否可以插入一條記錄,取到自增長id,然後就可以計算出之後所有數據的自增長id,而不再需要每條記錄都去取自增長id了。
但是這樣也有一個問題,就是在數據轉換導入的過程中,不能有其他的程序向錶中插入數據,不然會導致程序計算的自增長id匹配不上。而這個問題根本不存在,因為數倉的數據都是由原始錶計算插入的,在同一時間是沒有其他的任務寫這張錶,那麼我們就可以放心大膽的幹了。
金三銀四到了,送上一個小福利!
CodeChina開源項目:【一線大廠Java面試題解析+核心總結學習筆記+最新講解視頻】