背景:在開發公司一個內部服務上的查詢用戶反饋數據需求時,發現頁面響應過慢,每次查詢用戶反饋數據時耗時10s左右。雖然沒有用戶來反饋這個問題,但是明顯不正常,所以準備解決。
原因:在執行代碼中分段加入時間戳,獲取每段代碼的執行時間和總時間,以此來判斷耗時較多的代碼。在代碼中,有兩次rpc調用一個query服務,通過這個服務來查詢數據庫,第一個是查詢反饋數據,第二個是通過userId查詢用戶姓名。發現第二個服務平均耗時8600ms,佔用90%以上的時間。確定問題點後,開始優化。
波折:通過檢查查詢sql,發現sql中條件是userId >= minUserId and userId <= maxUserId,minUserId和maxUserId是通過遍歷反饋數據查找到的最大、最小userId,而userId是表的主鍵,即查詢已經使用了主鍵索引,似乎沒有優化的空間。
新線索:後來深入研究發現一般的默認查詢,結果集都有100多萬條數據,初步懷疑是數據量過大導致查詢結果返回給query服務時耗時過多。於是從這個角度出發,嘗試減少數據量。
第二次波折:查詢結果含有分頁的參數,初步設想,既然每次只顯示一頁的數據,那麼第二次rpc調用時只查詢這一頁數據的userId對應的姓名即可,這樣就能減少數據量。仔細查看代碼卻發現目前查詢大致流程如下
- 第一次rpc調用查詢全量的反饋數據
- 第二次rpc調用查詢反饋數據中userId對應的姓名,在反饋數據中設置對應userId的姓名
- 過濾一些不符合條件的反饋數據
- 對過濾結果進行分頁後返回
即分頁必須在過濾以後,否則無法保證數據能佔滿一頁,所以不能通過分頁參數來減少數據量。
新的希望:雖然分頁不能用於第二次rpc調用查詢,但是過濾分頁時並不需要姓名信息,這意味着第二次rpc調用可以發生在過濾分頁後,即只查詢某一頁反饋數據中userId的姓名,目前每頁尺寸是15條數據,這樣查詢結果集最大是15條數據。
結果:通過調整查詢中的一些步驟順序,避免了絕大多數多餘數據的查詢,減小了查詢結果數據集的大小。最終,第二次rpc調用平均耗時10ms,提高了800多倍速率,極大地縮短了響應時間。
反思:數據查詢前儘可能根據邏輯條件縮小查詢範圍,減少查詢結果集的大小,縮短查詢時間,提高查詢效率。