系統優化---功能優化心得

需求描述

錯題本功能要求展示最近一次答錯的小題,如果該題最近一次答對了將不會展示,同時展示信息還包含答題總數、答錯次數、連錯次數及其他邊緣信息

問題描述

當用戶答題數據量增大的時候,應該是幾千條的時候,每次查詢需要5秒左右的響應時間

問題分析

首先是硬件,由於我們的產品是平板,且設備整體性能比較差;其次,pad本地用的是sqlite數據庫不支持變量聲明,所以不能像mysql那樣比較輕鬆的通過變量來實現;再次,也是最主要的原因是因爲編寫的sql性能太差,大體思路是先進行數據全表掃描,篩選出判斷每條答題記錄對應該題最新的答題記錄是否爲錯(比較繞),然後進行聚合,然後是在代碼中遍歷集合出來的數據,分別通過sql查詢出該題對應的總記錄數、答錯次數、及連錯次數(差sql+循環),同事該接口由於需要分頁,所以上一個耗時sql又被重新調用了一次,最後導致接口特別耗時

優化分析

慶幸的是現在的我,優化接口不在只是從一個維度去考慮問題,優化是一個全局考慮的事情。硬件、架構、需求、代碼、sql等都是可以優化的地方,但是以目前整體狀況來看,從代碼和sql上優化還是最靠譜的,因爲硬件、架構和需求的優化成本都太高,而且這些都還不是問題的痛點,而且也不能體現和提升一個程序員的技術水平(不酷),最主要的是這些也不是我能決定的。

優化思路1(失敗)

主要從sql出發,將數據先通過記錄主鍵id和正確錯誤狀態(0:錯誤 1正確)倒序排序,然後按小題id進行聚合,得出最近答對小題記錄和沒有答對過的最大錯題記錄,將上一個記錄作爲臨時數據重新關聯答題記錄表,篩選出上一個記錄中答題狀態爲錯的記錄和id大於關聯id的數據(因爲大於的都是在最近一次答對之後連續答錯的)聚合出連錯次數,答題總數和錯誤次數在上一次查詢中已經聚合出不在描述。想想感覺應該是非常順當的一條死路,對是一條死路,因爲聚合和排序兩個一塊用並不能得到我們想要的結果(最起碼我當時在mysql5.7上測試的是這個結果),因爲是先聚合在排序,通過網上查找最終也沒有解決這個問題。

優化思路2(未採用)

創建用戶答題聚合表,用戶答題過程中共隨時更改該表中的數據,這個思路清晰簡單,但是需要添加新的表,而且需要大量修改業務代碼,項目本身處於一個相對穩定的狀態,如果加上這一段代碼後就需要重新整體測試代碼,影響比較大且需要人力比價高,所以最後放棄了

優化思路3(成功)

代碼+sql 首先是sql,大體思路是先聚合出每道小題的最大答題記錄id,同時聚合出作答次數及錯誤次數,然後以這個id重新關聯答題記錄表同事篩選出對錯狀態爲錯的(因爲上一步驟並不能聚合出最大答題記錄id的同時也展示出該記錄的對錯狀態),這一個加上分頁操作(因爲這些數據已經是想要的數據了,但是沒有包含連錯次數),然後在通過小題id關聯答題記錄表,得出分頁之後的小題的所有答題記錄,返回的肯定不是我們傳入的limit的數據量,肯定比這大,那應該是怎解決呢,連錯次數也沒有得到,通過sql已經很費勁了因爲這裏面有還包含中間答對的情況,所以最後決定通過代碼聚合,具體的就不在贅述了,因爲不是特別難。最後終於解決了

收穫

首先推翻了網上一貫流傳的“儘量避免使用子查詢,因爲子查詢性能不好”,其實好不好跟實際的業務需求是有很大關係的,比如我們產品的整體規劃,產品爲單機,受衆用戶未高考學生,所以數據量不會是幾百萬幾千萬那樣,很有可能都超不過4位數,而且本身子查詢在某些場景下性能還是比較好的,得益於最近看的《數據庫系統概念》、《INNODB內核》及《高性能mysql》幾本書,對於底層原理的瞭解,讓我對於業務的優化有了更深刻的認識,比如其中一個名詞叫做“延遲關聯”在這裏正好也用到了(開心),其次是,認識到任何封裝在提供了易用性的同時,也帶來了性能上的損耗,比如分頁插件,分頁插件知識簡單的再業務sql的外層有加了一層統計查詢來或得記錄的總數,但是殊不知要獲取記錄的總數可以通過性能更好的sql來獲取,這也是這次優化所採用的一種手段,最後就是通過java代碼聚合數據,代碼本身不是特別複雜,最大的收穫就懂得了優化不要只從一個角度去思考

心得

這次能夠優化成功且收穫這麼多,大部分都是得益於這半年看的書(《數據庫系統概念》、《INNODB內核》及《高性能mysql》還有一本講zk的),保持一顆不斷進步的心態,才能走的更長久

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