近期,資料中心系統負荷大,mysql服務器的CPU動輒達到90%以上,代碼和資料表存在很大優化空間,
這里分享一個定時任務批量處理資料的優化程序,
先介紹定時任務
先介紹下面2張資料表
| 欄位 | 資料量 | |
|
platform_order 平臺交易訂單表 |
有超過50多個欄位, 包括 主鍵自增id、客戶id、客戶名稱(冗余欄位)、服務商id(levy_id)、服務商名稱(levy_name,冗余欄位)、 付款方式、付款狀態、收款人、收款人收款賬號(卡號/支付寶/微信)、專案id、付款金額、渠道商、銷售代表、 創建時間、最近更新時間、付款完成時間,等等, |
550w,每天增量3w |
|
levy_info 服務商基礎資訊表 |
欄位包括 服務商id(levy_id)、服務商名稱(levy_name),等若干欄位 | 50條,很少新增 |
專案程式里有一個定時任務,每間隔5分鐘,定期為platform_order的冗余欄位levy_name賦值,也就是,根據levy表里的資訊來更新platform_order表,
最初的程式實作
我相信這是絕大多數程式員的實作方式,
【第一步】求count: select count(1) from platform_order where levy_name is null
【第二步】分頁從資料表獲取levy_name為null的記錄,例如每頁1000條,放到List集合里,
【第三步】遍歷List集合里的元素,根據記錄的levy_id去查levy_info表,得到levy_name,執行SQL:update platform_order set levy_name=#{levy_name} where id=#{id}
這個定時任務啟動后,不停刷日志,耗時≈3min
改進的程式實作
【第一步】求count:SQL同上
【第二步】如果count>0,則執行一條update陳述句:update platform_order a join levy_info b on a.levy_id=b.levy_id set a.levy_name=b.levy_name where a.levy_name is null
這個實作方式,java著手少了許多代碼,不過,資料庫倒是出現慢sql了,第二步的update陳述句耗時10~12s,
count耗時≈2s,整體耗時≈15s
洪荒之力,優化到200ms以內
【第一步】
不再是傻瓜式地一個 levy_name is null 條件了,而是再加一個id>#{maxId}條件, maxId 值從哪里來?每次定時任務執行完后將最大記錄id快取起來,當然,服務啟動后第一次是沒有快取的,就讓maxId=0,
再者,執行的sql不是簡單的count,而是 select levy_id, min(id) as minId,max(id) as maxId from platform_order where id>#{maxId} and levy_name is null group by levy_id
【第二步】
上面的分組查詢得到一個List集合,遍歷集合元素,同樣根據levy_id查levy_info表得到levy_info記錄,
然后,如果你跟得上我的節奏,你應該能猜到,執行這樣一個SQL:
update platform_order set levy_name=#{levy_name} where levy_id=#{levy_id} and id between #{minId} and #{maxId} and levy_name is nullView Code
要提到的一點是,根據levy_id獲取levy_info記錄,我使用了快取,快取24h,是不是很豪橫~
【第三步】
快取最大id ---> maxId
這么優化之后,job的耗時在100ms~200ms之間,這個耗時足可以令伙伴們尖叫!

當看到一些不好的代碼時,會發現我還算優秀;當看到優秀的代碼時,也才意識到持續學習的重要!--buguge
本文來自博客園,轉載請注明原文鏈接:https://www.cnblogs.com/buguge/p/16812025.html
<style>hr.signhr{width:80%;margin:0 auto;border: 0;height: 4px;background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0))}</style>
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/518706.html
標籤:Java
上一篇:JVM、JDK、JRE你分的清嗎
