師兄問我如何處理慢SQL。我在學校作的小Demo裏面數據量過小並無涉及到性能優化問題,可是思考這個問題倒以把數據庫優化給捋一捋。ios
傳統的學生思惟是很抽象的,好比一個SQL查詢,當作是一個程序的執行,無非是想辦法省內存,省磁盤空間,省CPU緩存,省調度,從這幾個角度去想,這也是學生常常會回答的幾條。sql
我以前的回答是這樣的:數據庫
上面說的對不對,大概來講,確實是有道理的,但這麼說能解決問題嗎,恐怕不能。實際狀況中咱們須要的首先不是解決方案,而是如何定位問題。一輛車子有異響,修理廠不去檢查異響在哪裏而是直接把四驅和引擎給換了一遍,這顯然不對的。換個角度來講,咱們首先要定位慢查詢是緣由,仍是結果,而是否是上來就一頓優化。緩存
什麼是慢查詢,從使用的角度來說,感覺直接的是時間維度的消耗,一個查詢的時間超過了你作基準測試時的時間,或者是這個時間讓使用者不能接受,都算慢查詢。安全
如何定位慢查詢,從總體來看,一個查詢要通過這麼幾步:性能優化
那麼能夠簡單從上概括一下,慢查詢的優化主要涉及:MYSQL自身的優化(Schema與數據類型的優化,建立高性能的索引,查詢性能優化)和MYSQL的外部優化。在尋找問題的過程當中,須要在各個層面設置追蹤點,肯定影響服務性能(我這裏說的是整個服務而不只僅是SQL)是在哪裏。若是肯定不是慢SQL的問題,測量的應該涉及服務器,客戶端,網絡這一塊,慢查詢的開始到結束的時間,若是是慢SQL的問題,那麼測量的應該是SQL開始到結束的時間,而慢SQL的開始到結束的時間又分爲開始到結束的時間又分爲執行時間和等待時間。其中,執行時間由子任務時間,從每一個子任務時間咱們能夠看到時間的佔用狀況,從而進行優化;等待時間則涉及系統間的影響和不一樣任務之間佔用磁盤的CPU的影響。服務器
回到我以前的回答,咱們依次捋一下,我說的這些回答是怎麼具體問題具體分析。網絡
硬件優化函數
這裏說硬件優化可能過於狹隘,這一塊應該不止是硬件優化,還有網絡,應用層,操做系統。我就統一稱爲外部環境優化。這一部分涉及三條:性能
1.操做系統優化
2.硬件優化
3.應用層優化
4.網絡配置
我主要講一下硬件優化和網絡配置,之後的再補。
硬件優化。許多不一樣的硬件均可以影響MYSQL的性能,可是最多見的倆個瓶頸應該是CPU和I/O資源。
CPU能夠經過查看CPU佔用來觀察,我前面只講了時間的消耗,那麼要不要講性能的消耗,我以爲能夠,可是不是必要的,好比MYSQL對服務器CPU、內存的佔用率,佔用率很好是好事嗎?我以爲是好事,這意味着服務器上更多的資源分配給了MYSQL,可是CPU的總利用率一直很高並且影響到了服務性能,就該考慮是否是要換CPU了。
I/O能夠經過操做系統中的I/O統計指令,如iostat來觀察。配置大量內存的最大緣由並非由於能夠在內存中保存大量數據,而是爲了不磁盤I/O。雖然咱們可使用索引來避免隨機I/O,可是使用緩存即便是隨機讀取也能夠省更多的操做,一個設計良好的數據庫緩存能夠提升很好的工做效率。
須要注意的是,並非足夠的內存就能夠徹底避免磁盤的讀取請求,在服務器重啓之後有時會出現讀取速度慢的時候,是由於服務器的緩存尚未「熱」起來,並且雖然讀寫能夠在內存中完成,可是寫的持久化依然要進行磁盤I/O。
針對緩存,通常可使用以下的方法:
1.屢次寫入,一次刷新(好比計數器)
2.I/O合併,(不一樣部分的數據在內存中修改,經過一次操做合併到一塊兒完成持久化)
硬盤有延遲和吞吐量,網絡也是。延遲和帶寬一般是網絡鏈接的限制因素,但更大的問題是出如今延遲上。由於TCP會嘗試重發,由於它的安全機制,由於TCP會積壓,由於它的鏈接隊列(這裏能夠修改MYSQL的back_log)。一個應用程序一般會傳輸不少很小的網絡包,最後每次傳輸的輕微延遲最終都會被累加起來,而不正常的網絡形成的丟包也會形成一樣的問題。
另外一個問題出如今DNS的損壞,由於當MYSQL收到一個鏈接請求時,它同時須要作正向查找和反向DNS查找。當問題出現時,會致使鏈接拒絕,嚴重至關於遭到了DDOS攻擊。所以在判斷這一塊的問題的時候,首先要監控網絡性能和網絡端口,若是DNS出現了問題,修改DNS,若是網絡出現了問題,聯繫運營商或者修改網絡設置。
使用索引
使用索引必定會提升查詢效率嗎,準確的說,應該是高性能的索引。要理解索引是如何工做的,首先在索引中找到對應的值,而後根據匹配的索引記錄找到對應的數據行。
索引涉及的東西好多,我過一陣子再寫。
-------
下面是草稿
使用索引:
通常你們能想到的就是使用索引了。可是要避免全表掃描,首先考慮在where,order by,group by 涉及的列上創建索引。
優化SQL語句:
經過explain,能夠看到SQL的執行效果,從而選擇更好的索引和優化查詢語句。好比:explain selext * from student。
查詢的時候不要用 * 號,這樣會返回你用不到的字段,最好是用具體的字段替代。
不在索引列上作運算或者使用函數。
查詢的時候儘可能使用 limit 減小返回的行數。
優化數據庫對象:
使用 procedure analyse() 函數對錶進行分析,這個函數能夠對錶中列的數據類型提出優化建議。表的數據類型的第一個原則是,能正確表示和存儲數據的最短類型。能小就小。好比:select * from student procedure analyse()。
分表。若是一個表中有些列經常使用有些不經常使用,就垂直拆分,即把主鍵和一些列放在一個表中,把主鍵和另一些列放在另外一個表總。若是都經常使用,這個一個表又太大了,那就按行拆分,大表拆小表,也叫水平拆分。
中間表。若是要常常對一個表進行aggregation,那麼我能夠把這些結果用一箇中間表存起來,這個也能夠理解成另外一種程度的分表。
分區。分區就是把一個表分紅多個區塊,這個區塊能夠在一個磁盤上,也能夠
硬件優化:
這個時候就是能用錢解決的東西就用錢解決,更好的CPU,更大的內存,性能更強的SSD。
MySQL自身優化:
在安裝Mysql的時候,裏面還有一個my.cnf配置文件,裏面能夠對各項參數進行優化調整,好比加大MySql的查詢緩存,加大數據庫鏈接池。
Schema與數據類型優化的我的理解
良好的表的設計能夠節省後期的維護成本。我在參與數據庫開發的過程當中數據量過小了,彷佛也沒有死扣細節以儘量地提高查詢地性能。
數據類型優化細節:
MySQL支持地數據類型特別多,可是一般咱們要從這麼幾個方面考慮咱們是要如何使用數據類型:
1.能正確存儲數據地最小地數據類型。好比:若是字符串大小是一個定長的值,或者很是短的列,使用char會比varchar更有效率,好比存儲一個Y/N值時,char只須要一個字節,而varchar(1)須要倆個字節,由於還須要以惡搞記錄長度的額外字節。
2.簡單地數據類型能存儲地就不要用複雜地數據類型,好比:使用時間內建類型好比DATATIME或者TIMESAMP而不是字符串存儲日期和時間,整形存儲IP地址等。
3.避免NULL。好比:雖然不少表均可以包含NULL,可是若是是查詢NULL列的時候可能會更復雜,好比當含NULL的列被索引時,每一個索引須要一個額外的字節。
必定要徹底範式化嗎?在課堂上老師教的咱們建表須要知足三範式,即1.每列原子性 2.每列與主鍵相關 3.每列與主鍵列直接相關 。可是實際上建表的時候必定要保持範式化設計嗎?咱們來看看範式的優勢:當數據比較好的範式的時候,不多有多餘的數據,表小,更新查找速度快。看起來挺不錯,可是範式化設計的schema的缺點一般在關聯上,稍微複雜一點的查詢語句在符合範式的schema上可能至少須要一次關聯,這也可能使得一些索引策略失效,好比範式化可能將列存放在不一樣的表中,而這些列若是在一個表中原本能夠數以一個索引。舉個例子,若是我要查看vip用戶的最近的10條信息:select message_text,user_name from message inner join user on message.user_id = user.id where user.account = vip order by message.published desc limit 10在這個查詢中,Mysql首先須要掃描message中的published字段的索引,對於每一行找到的數據,都要在user表李檢查這個用戶是否是vip用戶,若是隻有一小部分用戶的付費用戶,那麼效率是很是低下的。