日報表定時任務優化歷程

報表需求背景

報表是一個很常見的需求,在項目中后期往往會需要加多種維度的一些統計信息,今天就來談談上線近10個月后的一次報表優化優化之路(從一天報表跑需要五分鐘,優化至秒級)
需求:對代理商進行日統計
統計數據:門店數量、設備總數、當日訂單數/金額/退款/收益、門店七日新增數、30日0訂單門店數量
前置約束:未明確標明指定主庫操作 以及 事務,則默認代表走 從庫 以及 默認事務

先來看看這一版的流程:

// 以下所有查詢/統計 均為從MySQL中獲取按天 開始 循環(任務調度時可指定日期補償重跑,防止后續定時任務中斷,默認跑昨日數據)1. 獲取所有代理商(大幾千個)代理商列表 循環開始2. 門店統計2.1    獲取代理名下所有門店列表2.2    查詢代理近三十天內有訂單的門店ID,對比門店列表 得到:30日0訂單門店數量2.3    獲取代理名下七日新增門店3. 設備總數統計4. 訂單統計4.1    統計代理昨日訂單數/訂單金額/退款(訂單/收益 均是千萬級表)4.2    統計代理昨日收益代理商列表 循環結束5. 新開事務 且 指定主庫5.1    清理對應日期的統計數據5.2    對統計數據進行分批提交(mybatis拼接SQL,千條為一個批次,防止后續當日統計數據過多,導致SQL長度超限)5.3    事務提交
按天 結束 循環

以上流程跑當日耗時大約在4-5分鐘,乍一看其實并不慢,但此時距離上線已有九月有余,乍一算這個任務得跑20+小時
不管了,能跑就行,先上線再優化

after a long time
午夜驚醒,這玩意得優化哇,這也太不好用了
-_- 還債的時刻到了

第二版

思考:報表任務里都是一些MySQL查詢 以及 內存循環對比,且門店統計那塊是嵌套循環查詢,訂單的查詢時間也有點長
帶著這些思路去排查,發現幾個問題:

  1. 每個代理都需要去查詢一遍門店統計信息,這里網絡IO次數 = 總代理數量
    若每次50ms * 幾千,emm,怎么這么多…
  2. 訂單的查詢某些代理耗時很高,去看了下索引,emm,1 2 3 4 …8 9 10個索引
    了解到MySQL8.0是基于成本模型來生成執行計劃的,那么有可能是索引不完全匹配 或 執行計劃偏移,下面貼一下SQL與表當前索引
# 訂單統計SQL
SELECTcount( * ) orderTotal,sum( pay_amount ) AS orderAmount,sum( refund_amount ) AS refundTotal
FROMorder 
WHEREagent_id = #{groupId}AND pay_rev_time BETWEEN #{startDate} and #{endDate}    # 這個時間可能會有跨度# 貼下部分索引
uk_order_no            `order_no` ASC
idx_agent_id            `agent_id` ASC
idx_pay_rev_time    `pay_rev_time` ASC
idex_emp            `empower_time` ASC

發現問題,那么就開始一個個嘗試改造優化下:

問題一流程優化

1. 分組查詢所有代理 門店總數
2. 分組查詢所有代理 7 日新增門店數
3. 分組查詢所有代理 名下門店總數
4. 分組查詢所有代理 近三十天內有訂單的門店ID
5. 分組查詢所有代理 設備總數
6. 分組查詢所有代理 昨日收益金額
按天 開始 循環(任務調度時可指定日期補償重跑,防止后續定時任務中斷,默認跑昨日數據)7. 獲取所有的代理代理商列表 循環開始8. 門店統計8.1    內存中 獲取代理名下所有門店列表(時間復雜度O(1))8.2    內存中 查詢代理近三十天內有訂單的門店ID,對比門店列表 得到:30日0訂單門店數量(時間復雜度O(1))8.3    內存中 獲取代理名下七日新增門店(時間復雜度O(M+N) 代理門店列表 與 有訂單門店列表求交集)9. 訂單統計9.1    MySQL 統計代理昨日訂單數/訂單金額/退款9.2    內存中 統計代理昨日收益(時間復雜度O(1))10. 內存中 獲取設備總數統計(時間復雜度O(1))11. 新開事務 且 指定主庫11.1    清理對應日期的統計數據11.2    對統計數據進行分批提交(mybatis拼接SQL,千條為一個批次,防止后續當日統計數據過多,導致SQL長度超限)11.3    事務提交代理商列表 循環結束
按天 結束 循環

至此重跑,發現統計一天的數據已經達到秒級,這里給到一段真實執行時間

問題二SQL優化

看到這里就會有小伙伴有疑問了,為什么上面 9.1流程 中不采用預先一次性統計所有代理數據呢?
這里是為了引出第二個優化方向,不然這不就結束了嘛~~~

修改后打補丁繼續執行,又又又失敗了…

# 回顧上面的 訂單統計SQL,有兩個條件,分別是:agent_id、pay_rev_time
# 而這兩個字段也分別有自己的獨立索引,分別是:idx_agent_id、idx_pay_rev_time# 那么對于優化器就大概以下幾個策略來進行查詢:
#     1. 根據 idx_pay_rev_time索引來找到一段時間內數據,然后再根據agent_id 篩選出最終的結果
#     2. 根據 agent_id索引來找到具體代理商的數據,然后再根據pay_rev_time 篩選出最終的結果
#     3. 全表 掃# 在業務中,使用上述幾種方式去查詢都將不是最優解,而 agent_id、pay_rev_time又是此SQL的必填條件,
# 此時可以為他們創建一個聯合索引:ALTER TABLE order ADD INDEX idx_agentid_paytime (agent_id,pay_rev_time);
# 并且在SQL上強制使用此索引,防止執行計劃偏移SELECTcount( * ) orderTotal,sum( pay_amount ) AS orderAmount,sum( refund_amount ) AS refundTotal
FROMorder force index(idx_agentid_paytime)
WHEREagent_id = #{groupId}AND pay_rev_time BETWEEN #{startDate} and #{endDate}

后記

問題一流程優化解釋

此解題思路實際上是避免了循環查詢MySQL,以 一次慢查詢 來 優化后續的 多次快查詢

但事無絕對,在某些情景下,一次統計的慢查詢可能會令系統負載很高,甚至影響到實時業務,那么保持現狀:多次快查詢 可能會更優

少量多次 與 一次解決,需要根據業務以及系統現狀來衡量,有時候快并不是唯一的追求

參考資料

https://dev.mysql.com/doc/refman/8.0/en/cost-model.html
https://www.cnblogs.com/wcwen1990/p/6656611.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/10327.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/10327.shtml
英文地址,請注明出處:http://en.pswp.cn/web/10327.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基礎I/O:文件系統調用接口

文章目錄 文件系統調用接口open系統調用接口和C語言封裝文件描述符fd重定向 文件系統調用接口 open NAME//打開、創建 - 打開并可能創建文件或設備open, creat - open and possibly create a file or deviceSYNOPSIS#include <sys/types.h>#include <sys/stat.h>…

【C++算法】隊列相關經典算法題

1. N叉樹的層序遍歷 首先我們遇到這個題目&#xff0c;沒有任何思路&#xff0c;我們就可以來模擬一下層序的流程&#xff0c;首先我們肯定是訪問根節點1&#xff0c;訪問之后呢就是訪問下一層的最左節點3&#xff0c;此時第一層的節點1已經訪問過了就可以不要了&#xff0c;然…

[GESP樣題 四級] 填幻方和幸運數

B3940 [GESP樣題 四級] 填幻方 題目 在一個NN 的正方形網格中&#xff0c;每個格子分別填上從 1 到 NN 的正整數&#xff0c;使得正方形中任一行、任一列及對角線的幾個數之和都相等&#xff0c;則這種正方形圖案就稱為“幻方”&#xff08;輸出樣例中展示了一個33 的幻方&am…

ICode國際青少年編程競賽- Python-4級訓練場-嵌套for循環練習

ICode國際青少年編程競賽- Python-4級訓練場-嵌套for循環練習 1、 for i in range(3):Spaceship.step(4)for j in range(4):Dev.step(2)Dev.turnRight()Spaceship.turnLeft()Spaceship.step(4)Spaceship.turnRight()2、 for i in range(4):Spaceship.step(6)for j in range(3):…

Nginx或Tengine服務器配置SSL證書

目錄 前提條件 步驟一&#xff1a;下載SSL證書 步驟二&#xff1a;在Nginx服務器安裝證書 步驟三&#xff1a;驗證SSL證書是否配置成功 前提條件 已通過數字證書管理服務控制臺簽發證書SSL證書綁定的域名已完成DNS解析&#xff0c;即您的域名與主機IP地址相互映射已在Web服…

維修Philips IU22飛利浦四維多普勒彩超診斷儀 V6-2 L12-5 C8-4V深圳捷達工控維修

專為新時代而設計。專為更多而設計。 超聲波在抗擊 COVID-19 中的成像作用不斷擴大&#xff0c;并且對血管和心臟檢查的需求不斷增加&#xff0c;因此比以往任何時候都更有價值。飛利浦的超聲產品組合&#xff08;包括 EPIQ Elite&#xff09;為一線護理人員提供了寶貴的診斷支…

Intel處理器7z/XZ遇到 The failure in hardware

最近在使用Intel 12700H混合架構處理器的時候&#xff0c;一旦使用7z或者XZ算法壓縮東西就會出現如下的報錯&#xff1a; Internal Error: The failure in hardware (RAM or CPU), OS or program在檢查排除了內存、磁盤和OS的問題后&#xff0c;最終確定為Intel CPU的問題&…

Lazada、Shopee測評自養號,快速出單技巧全解析!

每個人都憧憬著自己的店鋪能夠擁有一款或多款引人注目的熱銷商品&#xff0c;這些商品不僅能為店鋪帶來可觀的收益&#xff0c;更重要的是它們能夠成為吸引顧客的強大磁石&#xff0c;顯著提升店鋪的整體流量。一旦這樣的爆款商品成功吸引顧客&#xff0c;其他產品也將隨之受到…

C++11:并發新紀元 —— 深入理解異步編程的力量(1)

hello &#xff01;大家好呀&#xff01; 歡迎大家來到我的Linux高性能服務器編程系列之《C11&#xff1a;并發新紀元 —— 深入理解異步編程的力量》&#xff0c;在這篇文章中&#xff0c;你將會學習到C新特性以及異步編程的好處&#xff0c;以及其如何帶來的高性能的魅力&…

Python:通過接口獲取公眾號的文章列表(但是開發文檔沒有這個接口)

&#x1f4da;博客主頁&#xff1a;knighthood2001 ?公眾號&#xff1a;認知up吧 &#xff08;目前正在帶領大家一起提升認知&#xff0c;感興趣可以來圍觀一下&#xff09; &#x1f383;知識星球&#xff1a;【認知up吧|成長|副業】介紹 ??感謝大家點贊&#x1f44d;&…

【LeetCode】每日一題:2960. 統計已測試設備

給你一個長度為 n 、下標從 0 開始的整數數組 batteryPercentages &#xff0c;表示 n 個設備的電池百分比。 你的任務是按照順序測試每個設備 i&#xff0c;執行以下測試操作&#xff1a; 如果 batteryPercentages[i] 大于 0&#xff1a; 增加 已測試設備的計數。 將下標在 [i…

力扣HOT100 - 35. 搜索插入位置

解題思路&#xff1a; 二分法模板 class Solution {public int searchInsert(int[] nums, int target) {int left 0;int right nums.length - 1;while (left < right) {int mid left ((right - left) >> 1);if (nums[mid] target)return mid;else if (nums[mid…

【qt】設計器實現界面

設計器實現界面 一.總體思路二.具體操作1.創建項目2.粗略拖放3.水平布局4.垂直布局5.修改名字6.轉到槽7.實現槽函數 一.總體思路 二.具體操作 1.創建項目 這次咱們一定要勾選Generate form哦。 因為我們要使用設計器進行拖放。 2.粗略拖放 這里用到了復選框&#xff1a;C…

[數據集][目標檢測]管道焊縫質量檢測數據集VOC+YOLO格式1134張2類別

數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;1134 標注數量(xml文件個數)&#xff1a;1134 標注數量(txt文件個數)&#xff1a;1134 標注…

python元類與C#、Java中的反射

Python的元類和C#中的反射 在概念上有一定的相似性&#xff0c;但它們的目的和使用方式有所不同。 Python的元類&#xff1a; 元類&#xff08;Metaclass&#xff09;是控制類創建的類。它們定義了類的創建過程&#xff0c;可以修改類的行為。元類通過定制類的創建過程&…

算法訓練營第二十五天 | LeetCode 669 修剪二叉樹、

LeetCode 669 修剪二叉樹 這題用層序遍歷雙指針刪除不符合條件的節點即可。具體是要用到一個虛擬根節點&#xff0c;雙指針中prev指針每次指向隊列頂元素&#xff0c;cur指針先指向prev左子節點&#xff0c;用循環去除這個位置上不符合條件的節點并連上繼承節點&#xff0c;內…

“我們堅持開源!”阿里云發布“地表最強”中文大模型:半年一迭代、性能翻倍?

5 月 9 日&#xff0c;在通義大模型發布一周年之際&#xff0c;阿里云大模型生態迎來一次重大升級&#xff0c;主要有“四個最”&#xff1a; 通義千問 2.5 正式發布&#xff0c;“模型性能全面趕超 GPT-4 Turbo&#xff0c;成為地表最強中文大模型”&#xff1b;Qwen1.5-110B…

卷積特征圖與感受野

特征圖尺寸和感受野是卷積神經網絡中非常重要的兩個概念&#xff0c;今天來看一下&#xff0c;如何計算特征尺寸和感受野。 特征圖尺寸 卷積特征圖&#xff0c;是圖片經過卷積核處理之后的尺寸。計算輸出特征的尺寸&#xff0c;需要給出卷積核的相關參數包括&#xff1a; 輸…

PC端與bluetooth藍牙虛擬串口通信

應該采用RFCOMM虛擬串口方式來進行通信&#xff0c;原理跟socket通信類似&#xff0c;不同的是使用的通信協議不同&#xff0c;本人結合相關的API&#xff0c;做了以下最簡單的封裝。 1、獲取本地藍牙設備與附近藍牙設備信息 2、通信類 /* 通信類&#xff1a;只是對于客戶端通…

基于Python實現單例模式

目錄 1、使用裝飾器實現 2、使用__new__方法實現 單例模式是一種設計模式&#xff0c;它確保一個類只有一個實例&#xff0c;并提供一個全局訪問點來訪問這個唯一實例。這種模式在多種場景中都非常有用&#xff0c;以下是單例模式的一些常見應用場景&#xff1a; 應用程序的…