一、最佳化的思路和原則有哪些
1、優化更需要最佳化的查詢
2、定位最佳化物件的效能瓶頸
3、 明確優化的目標
4、 從Explain入手
5、 多使用profile
6、 永遠用小結果集驅動大結果集
7、 盡可能在索引中完成排序
8、 只取出自己需要的欄位(Columns)
9、 僅使用最有效的篩選條件
10、盡可能避免複雜的join
相關免費學習推薦:mysql影片教學
1、最佳化更需要最佳化的查詢
高並發的低消耗(相對)的查詢對整個系統影響遠大於低並發高消耗的查詢。
2、定位優化物件的效能瓶頸
在拿到一條需要優化的查詢時,我們首先要判斷出這個查詢的瓶頸到底是IO還是CPU 。到底是資料庫存取消耗多還是資料的運算(如分組排序)消耗多。
3、明確優化的目標
了解資料庫目前整體狀態,就能知道資料庫所能承受的最大壓力,也就是我們知道最悲觀狀況;
要把握該查詢相關的資料庫物件信息,我們就能知道最理想和最糟糕狀態下需要消耗多少資源;
要知道該查詢在應用系統中的地位,我們可以分析出改查詢可以佔用系統資源的比例,也能夠知道查詢的效率對顧客的體驗影響有多大。
4、從Explain入手
Explain能夠告訴你這個查詢在資料庫中是一個什麼樣的執行計畫來實現的。首先我們需要有個目標,透過不斷調整嘗試,再藉助Explain來驗證結果是否滿足自己的需求,直到得到預期的結果。
5、永遠用小結果集驅動大結果集
很多人喜歡在SQL優化的時候說用「小表驅動大表”,這個說法是不嚴謹的。因為大表經過where條件過濾後回傳的結果集不一定就比小表所回傳的結果集大,這個時候還用大表驅動小表,就會得到相反的效能效果。
這樣的結果也非常容易理解,在 MySQL 中的 Join,只有 Nested Loop 一種 Join 方式,也就是MySQL 的 Join 都是透過嵌套循環來實現的。驅動結果集越大,所需循環的此時就越多,那麼被驅動表的訪問次數自然也就越多,而每次訪問被驅動表,即使需要的邏輯IO 很少,循環次數多了,總量自然也不可能很小,而且每次循環都無法避免的需要消耗CPU,所以CPU 運算量也會跟著增加。所以,如果我們只以表的大小來作為驅動表的判斷依據,假若小表過濾後所剩下的結果集比大表多很多,結果就是需要的嵌套循環中帶來更多的循環次數,反之,所需要的循環次數就會更少,總體IO 量和CPU 運算量也會少。而且,就算是非 Nested Loop 的 Join 演算法,如 Oracle 中的 Hash Join,同樣是小結果集驅動大的結果集是最優的選擇。
所以,在優化Join Query 的時候,最基本的原則就是“小結果集驅動大結果集”,透過這個原則來減少嵌套循環中的循環次數,達到減少IO 總量以及CPU 運算的次數。盡可能在索引中完成排序
6、只取出自己需要的欄位(Columns)
對於任何查詢,傳回的資料都是需要透過網路封包傳送給客戶端,如果取出的Column越多,需要傳輸的資料量自然會越大,不論從網路頻寬還是網路傳輸緩衝區來看,都是一種浪費。
7、僅使用最有效的過濾條件
舉個例子一個用戶表user有id和nick_name等字段,索引是id和nike_name兩個索引,下面是兩個查詢語句
#1 select * from user where id = 1 and nick_name = 'zs'; #2 selet * from user where id = 1
兩個查詢得到結果是一樣的,但是第一個語句用到的索引佔用空間是比第二個語句大很多的。佔用空間大也代表著要讀取的資料量也更多。 ,也就是說2的查詢語句才是最優查詢。
8、避免複雜的join查詢
# 我們的查詢語句所涉及的表格越多,所需要鎖定的資源就越多。也就是說,越複雜的 Join 語句,所需要鎖定的資源就越多,所阻塞的其他執行緒就越多。相反,如果我們將比較複雜的查詢語句分拆成多個較為簡單的查詢語句分步執行,每次鎖定的資源也會少很多,所阻塞的其他線程也要少一些。
可能很多人會有疑問,將複雜 Join 語句分拆成多個簡單的查詢語句之後,那不是我們的網路互動就會更多了嗎?網路延時方面的整體消耗也就更大了啊,完成整個查詢的時間不是反而更長了嗎?是的,這種情況是可能存在,但並不是肯定就會如此。我們可以再分析一下,一個複雜的查詢語句在執行的時候,所需要鎖定的資源比較多,可能被別人阻塞的機率也就更大,如果是一個簡單的查詢,由於需要鎖定的資源較少,被阻塞的機率也會小很多。所以 較為複雜的連線查詢也有可能在執行前被阻塞而浪費更多的時間。而且我們的資料庫所服務的並不是單單這一查詢請求,還有很多很多其他的請求,在高並發的系統中,犧牲單一查詢的短暫回應時間而提高整體處理能力也是非常值得的。優化本身就是一門平衡與取捨的藝術,只有懂得取捨,平衡整體,才能讓系統更優。
二、利用Explain和Profiling
#1、Explain使用
各種資訊來展示
欄位 | 說明 |
---|---|
#ID | 在執行計畫中查詢的序號 |
Select_type | 查詢類型: DEPENDENT SUBQUERY : 子查詢中內層的第一個SELECT,依賴外部查詢結果集; DEPENDENT UNION :子查詢中的UNION中從第二個SELECT 開始的後面所有SELECT,同樣依賴外部查詢結果集; PRIMARY: 子查詢中的最外層查詢,不是主鍵查詢; SUBQUERY:子查詢內層查詢的第一個SELECT,結果不依賴外部結果集; UNCACHEABLE SUBQUERY:結果集無法快取的子查詢; UNION:UNION語句中第二個SELECT開始的後面所有SELECT,第一個SELECT為PRIMARY UNION RESULT:UNION中的合併結果 |
#Table | 所存取的資料庫中表格名稱 |
#TYPE | 存取方式: ALL: 全表掃描 const: 常數,最多只有一筆記錄匹配,由於是常數,所以實際上只需要讀一次 eq_ref: 最多只有一條符合結果,一般是主鍵或唯一索引來存取的 index: 全索引掃描 range: 索引範圍掃描 ref: jion語句中被驅動表索引的參考查詢 system: 系統表,表中只有一行資料 |
Possible_keys | 可能會用到的索引 |
使用的索引 | |
索引長度 | |
#估算出來的結果集記錄條數 | |
#額外資訊 |
以上是MySQL查詢優化詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!