java 性能優化:存儲過程的優化與多線程的限制

  在上篇《java 併發:多線程鎖計數器》中提到過,在工作中碰到一個較大數據量的處理模塊。在上篇中使用多線程解決了數據導入的問題,而在數據導入後碰到了較大數據量的邏輯處理和更新問題,爲了在儘量短的時間內完成數據處理,我們開發組將整個數據處理過程拆分成兩個存儲過程和一段java代碼。
  我負責其中一個存儲過程,整個存儲過程的邏輯就是通過數據的Code字段規則,分析數據與數據之間是否存在父子關係,並將這種關係通過Parent_Id實體化。
  存儲過程完成後速度依然很慢在4分鐘左右,在不斷的探索和測試後終於將時間縮短到2-3s內。在此過程中學到了很多,在此記錄。

存儲過程之優化

存儲過程核心Code

  --遍歷WBS編碼所有長度,即所有層級
  for i in code_length loop
  
    m_num := i.clength - s_code;
    for frecord1 in (select *
                       from sgt_wbs
                      where PLAN_ID = planId
                        and length(CODE) = i.clength) loop
    
      -- 如果爲頂級編碼則只更新層級
      if (i.clength = min_code) then
        update sgt_wbs t
           set t.node_level = n_level
         where length(code) = i.clength;
        exit;
      end if;
    
      --更新WBS節點的parent_id
      update sgt_wbs t
         set t.parent_id  = (select id
                               from sgt_wbs
                              where code = substr(frecord1.code,
                                                  0,
                                                  i.clength - m_num)
                                and plan_id = planId),
             t.node_level = n_level
       where t.CODE = frecord1.code
         and t.plan_id = planId;
    
    end loop;
  
    commit;
  
    s_code  := i.clength;
    n_level := n_level + 1;
  
  end loop;

存儲過程測試及運行

1. 存儲過程運行
begin
  -- Call the procedure
  sgt_update_pid(planid => :planid);
end;                    
2. 存儲過程的測試

  整個過程使用的數據庫連接工具爲PL/SQL

  • 首先在存儲過程上右擊選中添加調試信息,然後再次選中測試


  • 然後添加變量數據,並執行


  • 頂部工具欄中常用工具
      常用的就兩個按鈕:按鈕1和按鈕2 ,按鈕1爲直接運行存儲過程,按鈕2爲單步執行存儲過程,類似java的debug。按鈕1 可以直接測試存儲過程是否能夠執行成功,而按鈕2一般爲在存儲過程出錯的過程中進行單步調試


  • 單步調試
      在調試過程中可以添加觀察變量,可以觀察變量在運行過程中值得變化,便於錯誤排查和調試


3. 存儲過程概覽圖

  在存儲過程中想要查看整個代碼用時情況需要使用概覽圖

  • 選中概覽圖按鈕
      如果想要查看存儲過程的時間分佈是無法同時單步調試的,需要直接執行


  • 執行
      在使用概覽圖的功能時是不能測試的,需要直接運行


  • 查看執行計劃
      在執行後,可以在頂部選擇概覽圖查看整個存儲過程中時間分部,並對耗時部分進行鍼對的優化


存儲過程優化

  在測試通過並使用概覽圖分析後發現了影響時間的code


1.分析耗時code

  我們可以發現存儲過程中大部分時間都消耗在更新語句中,在單獨對此語句做分析,並獲取該語句的執行計劃(F5)

  • 可優化代碼
      update sgt_wbs t
         set t.parent_id  = (select id
                               from sgt_wbs
                              where code = substr(frecord1.code,
                                                  0,
                                                  i.clength - m_num)
                                and plan_id = planId),
             t.node_level = n_level
       where t.CODE = frecord1.code
         and t.plan_id = planId;
  • 執行計劃



      通過執行計劃,我們可以發現更新過程中 子查詢是最耗時的操作,所以我們優化的重點放在了這個子查詢中。
      但是子查詢語句很簡單,並沒有優化空間,所以這裏我們爲查詢字段創建了索引來加快查詢速度

2.創建索引並測試

  當創建索引後,再次測試存儲過程,原來需要360多秒的時間,縮短到了2-3秒鐘,說明優化是有效的,並解決了數據處理時間過長的問題

多線程的限制

  在上篇文章中,使用多線程優化數據導入後,還想要在加快數據導入速度,最直接的反應是提高線程數。所以在此思想上做了一些列的測試

  • 數據量16000條
百分比(鎖) 線程數 數據校驗 時間
7 2.30m
7 32s
7 2.40m
14 2.33m
14 29s
14 2.40m

  通過比對測試發現線程數的增多在無數據校驗和變量鎖的情況下,多線程會提升導入速度,減少時間,但是一旦有了變量鎖和校驗,一倍多的線程速度反而慢了下來。
  測試直觀的表明,線程的確能提升導入效率,但是是有極限的,一旦超過最優線程數量,數據導入速度反而會出現下降的情況。可見線程是有限制的,一定要將線程數定在一個合理的範圍內,否則過多的線程不但會拖慢運行速度還會消耗服務器資源,導致整個應用響應變慢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章