1. 程式人生 > 程式設計 >淺談關於SQL優化的思路

淺談關於SQL優化的思路

零、為什麼要優化

  • 系統的吞吐量瓶頸往往出現在資料庫的訪問速度上
  • 隨著應用程式的執行,資料庫的中的資料會越來越多,處理時間會相應變慢
  • 資料是存放在磁碟上的,讀寫速度無法和記憶體相比

一、觀察

MySQL優化≠SQL語句優化,理解這一點非常重要,雖然大部分時候我們都在調優SQL語句。

然而,MySQL的優化卻是始於觀察,而且有時候觀察幾分鐘,幾小時就能得出結論的,可能要觀察一天以上。

這麼做的目的很明顯,就是為了幫助我們定位問題所在。 比如:MySQL的負載會在固定的某個時間節點突然暴漲,或者一請求某幾個頁面就產生了較為明顯的延遲,甚至影響了隨後的各個請求等。

觀察的手段有多種多樣,阿里雲有強大的RDS

控制檯,也可以自建一套監控平臺,最次的就是臨時跑個shell指令碼,收集MySQL執行狀況。 觀察的指標也不盡相同,最知名的 show status 命令列出的指標就能不下200個,所以觀察也要有所取捨。 經常受人關注的指標有當前連線數以及最大連線數,當前執行的執行緒數,慢查詢數量等。

二、分析

將觀察的結果做進一步分析,也就形成了不同的解決思路。

可能是某個時間節點快取失效,導致MySQL的負載激增,可以設法將快取失效的時間節點儘可能均勻的分攤在一天24小時中,或者找個訪問量較少的時段重新整理快取。

可能是SQL語句存在潛在問題,在某些情況下會有效能問題,可以用 show full processlist

定位是哪個庫,也可以開啟慢查詢,直接定位到有問題的SQL語句,使用explain分析語句執行計劃。可能加個索引能解決問題,也有可能join太多表,需要拆分查詢,也有可能單表體量過大,要拆表了。

可能是機器本身效能問題,所謂“巧婦難為無米之炊”,這個時候要考慮擴容了。

三、解決

在分析階段已經提及了大部分解決手段了,最後總結一下:

1、引入快取,當然,這是一把雙刃劍,要想用的恰如其分,還是需要一定的功力。快取也分兩方面的,一方面是MySQL的內部快取機制,MySQL提供了多種快取引數的配置,比如查詢的結果集快取,結果集排序的快取,可根據實際情況進行調整。另一方面是MySQL之外的快取,比如Redis+MySQL的架構,開啟了Hibernate(Mybatis)的快取功能。快取的引入無非是想減輕MySQL的查詢負擔,但是必須在效能穩定性與資料時效性之間取得平衡。

2、SQL語句有效能問題,這種情況時有發生,通常是上線之前未能做一個完整的基準測試,而只是簡單的功能性測試。當資料量積累到一定程度之後,SQL效能問題就集中爆發出來了。所以,在寫完SQL之後,要養成explain的習慣,將潛在的效能問題扼殺在萌芽中。當然,我們也要避免“過度優化”,我們要預見得到一張表是讀取次數多,還是更新次數多,資料量會不會爆發性增長,還是增長十分緩慢。當然,寫SQL語句也要遵循一定的原則,比如什麼時候用IN查詢,什麼時候用EXISTS謂詞,在JOIN之前是不是可以精簡一部分表資料,建立的索引能否正確派上用場……

3、必要的時候,可以對機器進行擴容,當然系統的整體架構也可以考慮進行優化,搭建MySQL叢集,可靠性和可用性都能得到大幅提升。

四、補充:SQL正規化

1NF

每一個分量必須是不可分的資料項。

特點:

  • 有主鍵,且主鍵不能為空。
  • 欄位不能再分。

2NF

在正規化一的基礎上,且每一個非主屬性完全函式依賴於碼。

特點:

  • 滿足第一正規化。
  • 表中的每一個非主屬性,必須完全依賴於本表碼。
  • 只有當一個表中,主碼由兩個或以上的屬性組成的時候,才會出現不符合第二正規化的情況。

3NF

在滿足第二正規化的基礎上,且每一個非主屬性既不部分依賴於碼也不傳遞依賴於碼。

特點:

  • 滿足第二正規化。
  • 非主屬性不能傳遞依賴於碼。

** BCNF**

在滿足第三正規化的基礎上,且不允許主鍵的一部分被另一部分或其它部分決定。

特點:

  • 滿足第三正規化。
  • 所有非主屬性對每一個碼都是完全函式依賴。
  • 所有的主屬性對每一個不包含它的碼,也是完全函式依賴。
  • 沒有任何屬性完全函式依賴於飛碼的任何一組屬性。

以上是對MySQL優化的框架性思考。