前言
注:這里討論的場景在於MIS,OA一類的系統
大部分同學在看到這個問題的時候,第一反應是糟糕的SQL語句,沒有加索引,這甚至已經成為一種慣性思維。
當發現性能出問題的時候,一般都會想到加個索引,或者改造下連接方式,去掉“not exists”諸如此類,但效果往往不太理想,或過一段時間后,效果又不理想了,此時,一般大家都會覺得問題在於自己還不是大神。
正文
今天給大家分享的就是:為了提高性能,不是大神的我們還有多少方法可以采取?
性能有三大殺手:1)糟糕的SQL使用;2)糟糕的數據結構;3)糟糕的業務模型
下面舉一個實際的例子,在EPO物資采購系統中的需求跟蹤功能中,可以查詢到所有歷史提交的需求申請單。查詢包含從需求申請->需求受理->訂單->驗收入庫->通知領用->發放完成所有環節的狀態。最初的做法是通過join將需求表、需求受理表、訂單表、驗收表、領用通知表和發放表連接起來形成一張視圖。當數據量小的時候,看起來一切都是那么的完美,但是后來就不那么美好了。於是,后來我們采取了一系列的優化。
階段一:物化視圖
當join的時候,問題出現在join的計算過程,數據量大了,計算耗費就會大,性能便會下降。不過,當問題來的那天,對於這種問題,大家是非常坦然的面對,做一張物化視圖就可以了,每天晚上計算一下,第二天查詢物化視圖即可。利用原生的SQL功能,物化視圖,對於大家來說手到擒來,投入低,收益高,效果立竿見影。
物化視圖:犧牲實時性,犧牲存儲空間,換取性能提升。
階段二:改變數據結構
隨着數據量加大,我們發現,物化視圖的計算越來越慢,雖然是放到晚上,但是隨着大家都認識到物化視圖可以解決問題,大批量開始使用物化視圖,且都放到晚上,濫用的程度甚至都驚動了DBA,晚上的DB負荷居然超過白天的業務高峰運行期。
這個場景下的物化視圖隱藏的一個問題,就是會重復計算那些永遠不會發生變化的數據。比如,有一張2010年的需求單,申請的是電腦,公司規定電腦4年報廢,如果我們在2015年跑物化視圖時,那張需求單對應到的數據,就永遠不會變化;但在每次物化過程這張需求單都會被join到視圖中,而join的過程又會產生計算花費。
此時我們要做的就是通過數據結構的改變,干掉那些無效的計算。此時會有多種選擇,分離歷史數據、實體化表等。我們采取的是實體化表的方式,實體化表上會對需求單進行區分,比如說剛剛提到的報廢的需求單或領用完成的需求單,這類需求單是再也不會發生改變的,我們給予不會變化
標示。而對於那些還未領用完成的需求單,我們標示為待計算
,對於那些待計算
的需求單我們每天晚上重新計算一次,刪除原有數據,填充最新數據。在目前的數據情況下,待計算的需求單占總單的5%以內,相比之前的方式我們至少省去了95%的無效計算過程。
改變數據結構:犧牲存儲空間,干掉無效計算過程,從而有效降低數據庫負荷。
階段三:優化業務模型
需求跟蹤中有一個查詢條件是物料名稱,對於這類文本型的查詢條件,99%的同學選擇都是“like %XYZ%”,但只有一半的同學知道,這種寫法使用不到索引,這一半同學中又有99%的同學都會認為這是沒有辦法的。確實,在技術上99%的人都想不到辦法,在技術上這個問題是無解的,因為我們都不是大神。不過可以分享給大家的是,這不是一個錯誤的SQL寫法,而是一個糟糕的業務模型。
比如說,我們通過后台可以分析出,大家喜歡用“電腦”、“主機”這類關鍵字,而輸入“電腦”在我們物料庫中對應肯定是“平板電腦”、“筆記本電腦”,“主機”對應的一定是“電腦主機”,我們在后台通過將“電腦”轉化為“平板電腦”、“筆記本電腦”、“電腦主機”,“主機”轉化“電腦主機”,便可以使用“like 電腦主機%”、“like 平板電腦%’、”like 筆記本電腦%”。通過業務模型的優化,再選擇合適的SQL語句。上面例子中,80%的查詢條件,都可以在后台轉化為“XYZ%”的方式,進而可以使用到了大家耳熟能詳的索引。
優化業務模型:通過運營數據分析,優化查詢條件,更好使用我們已知的SQL技巧。
當我們不是大神的時候,我們在發現性能問題的時候,我們的分析方式可以是:你有沒有犯常識性的SQL錯誤?你有沒有選擇合適的數據結構?你有沒有思考過業務模型非常糟糕?