尊嘟假嘟?三行代码提升接口性能600倍
一、背景
??業務在群里反饋編輯結算單時有些賬單明細查不出來,但是新建結算單可以,我第一反應是去測試環境試試有沒有該問題,結果發現沒任何問題!!!
??然后我登錄生產環境編輯業務反饋有問題的結算單,發現查詢接口直接504網關超時了,此時心里已經猜到是代碼性能問題導致的,接來下就把重點放到排查接口超時的問題上了。
二、問題排查
遇到生產問題先查日志是基本操作,登錄阿里云的日志平臺,可以查到接口耗時竟然高達469245毫秒!
這個結算單關聯的賬單數量也就800多條,所以可以肯定這個接口存在性能問題。
但是日志除了接口耗時,并沒有其他報錯信息或異常信息,看不出哪里導致了接口慢。
接口慢一般是由如下幾個原因導致:
- 依賴的外部系統慢,比如同步調用外部系統的接口耗時比較久
- 處理的數據過多導致
- sql性能有問題,存在慢sql
- 有大循環存在循環處理的邏輯,如循環讀取exel并處理
- 網絡問題或者依賴的中間件比較慢
- 如果使用了鎖,也可能由于長時間獲取不到鎖導致接口超時
當然也可以使用arthas的trace命令分析哪一塊比較耗時。
由于安裝arthas有點麻煩,就先猜測可能慢sql導致的,然后就登錄阿里云RDS查看了慢sql監控日志。
好家伙一看嚇一跳,sql耗時竟然高達66秒,而且執行次數還挺多!
我趕緊把sql語句放到數據庫用explain命令看下執行計劃,分析這條sql為啥這么慢。
EXPLAIN SELECT DISTINCT(bill_code) FROM `t_bill_detail_2023_4` WHERE
(settlement_order_code IS NULL OR settlement_order_code = 'JS23122600000001');
分析結果如下:
如果不知道explain結果每個字段的含義,可以看看這篇文章《長達1.7萬字的explain關鍵字指南!》。
可以看到掃描行數達到了250多萬行,ref已經是最高效的const,但是看最后的Extra列
Using temporary 表明這個sql用到了臨時表,頓時心里清楚什么原因了。
因為sql有個去重關鍵字DISTINCT,所以mysql在需要建臨時表來完成查詢結果集的去重操作,如果結果集數據量比較小沒有超過buffer,就可以直接在內存中去重,這種效率也是比較高的。
但是如果結果集數據量很大,buffer存不下,那就需要借助磁盤完成去重了,我們都知道操作磁盤相比內存是非常慢的,時間差幾個數量級。
雖然這個表里的settlement_order_code字段是有索引的,但是線上也有很多settlement_order_code為null的數據,這就導致查出來的結果集非常大,然后又用到臨時表,所以sql耗時才這么久!
同時,這里也解釋了為什么測試環境沒有發現這個問題,因為測試環境的數據不多,直接在內存就完成去重了。
三、問題解決
知道了問題原因就很好解決了,首先根據SQL和接口地址很快就找到出現問題的代碼是下圖紅框圈出來的地方
可以看到代碼前面有個判斷,只有當isThreeOrderQuery=true時才會執行這個查詢,判斷方法代碼如下
然后因為這是個編輯場景,前端會把當前結算單號(usedSettlementOrderCode字段)傳給后端,所以這個方法就返回了true。
同理,拼接出來的sql就帶了條件(settlement_order_code IS NULL OR settlement_order_code = 'JS23122600000001')。
解決起來也很簡單,把isThreeOrderQuery()方法圈出來的代碼去掉就行了,這樣就不會執行那個查詢,同時也不會影響原有的代碼邏輯,因為后面會根據篩選條件再查一次t_bill_detail表。
改代碼發布后,再編輯結算單,優化后的效果如下圖:
只改了三行代碼,接口耗時就立馬從469245ms縮短到700ms,性能提升了600多倍!
四、總結
感覺壓測環境還是有必要的,有些問題數據量小了或者請求并發不夠都沒法暴露出來,同時以后寫代碼可以提前把sql在數據庫explain下看看性能如何,畢竟能跑就行不是我們的追求??。
總結
以上是生活随笔為你收集整理的尊嘟假嘟?三行代码提升接口性能600倍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对比Spring Boot中的JdbcC
- 下一篇: Skywalking(8.7)安装以及d