資料庫優化,是乙個存在了幾十年的問題,更是每乙個後端開發者精進路上必須掌握的技能。
而效能優化的核心,就是摳門。在完成功能的前提下:對於cpu,執行越少的**,那麼所需要的cpu時間就越少,因此程式就會越快; 對於io,執行越少次數的i/o,阻塞於i/o的時間就會越少;對於網路,傳輸越少的資料,那麼所需要的時間就會越少。
對於mysql的優化,也是一樣的。接下來我們來看看mysql優化的幾個步驟:
首先要找到問題所在
效能測試,重現問題,這是進行效能優化的前提。因此我們需要靠一些工具,例如壓測工具、慢查詢日誌等,定位到問題,知道我們 遇到的問題,然後才能解決問題。如果定位到多個效能問題,那麼需要進行乙個優先順序(效能影響程度)的排序,從影響最大的開始 逐次解決。
常見的效能指標包括:吞吐量:指的是單位時間內執行的事務的數量。
併發性:指的是在任意時間有多少同時發生的併發請求。
可擴充套件性:指的是能否讓資料庫的效能隨著併發量的增加而線性增長。
而常見的測試方式就是,一方面逐步加大查詢量(或寫入量),另一方面定時收集效能資料,從而進行觀察。理想情況下可以通過圖表 的方式進行展示,這樣可以快速獲得乙個直觀的資料表示。此處推薦prometheus + mysql exporter。
資料庫快取
mysql有對查詢進行快取,但是這要取決於配置是否開啟,可以參見 此處the query cache is deprecated as of mysql 5.7.20, and is removed in mysql 8.0. 注意,mysql 8.0 移除了此功能。
開啟了query cache之後,mysql會對查詢進行快取,快取的規則是對輸入的sql進行hash計算,如果下一次的sql算出來的hash得到 相同結果,那麼直接返回結果,而不會再次去查詢。
但是此處注意,由於是對sql進行hash計算,所以只要sql有一丁點的變動,比如多了乙個空格,那麼就會計算出乙個不同的hash值, 從而不會從快取中讀取結果。此外只要查詢語句中有任何不確定的引數,例如函式 now() 或者類似的自定義函式、儲存函式、使用者變數、 臨時表,mysql庫中的系統表,或者任何包含對列級別許可權的表,都不會被快取。
而另一方便,由於所有的輸入都會進行一遍快取查詢,此處也有可能會成為效能瓶頸。
資料庫schema的設計
schema設計的好,那麼就能省事很多。資料庫設計中,有資料庫正規化和反資料庫正規化兩種極端。通常來說,我們會糅合兩種方向,取 乙個適中的度。遵循資料庫正規化的好處有資料庫操作會更快、沒有重複資料等,而反資料庫正規化的好處有避免隨機io而加快查詢速度等。
一般來說,資料庫schema的設計遵循這麼幾點:選取正規化和反正規化中合適的度,但是這個度和具體業務有關
schema不應該有太多的列,遵循最小原則,即無用的列,就不放此表中
資料型別同樣遵守最小原則,即選取合適,但又不浪費的資料型別。例如用bool來儲存true和false,用int來儲存id等等。
索引設計
在《資料庫索引設計與優化》一書中提出了乙個非常好的概念:三星索引。我們將會看到如何設計乙個三星索引。不過在此之前,我們會 先看看常見的索引型別以及他們的特性。b-tree索引。b-tree索引適用於這麼幾種查詢:精準匹配,例如 where a = 'a';
最左字首匹配,即只使用索引的第一列,例如有乙個聯合索引是 (user_id, user_name),當查詢條件是 where user_id=1 時也可以用上這個索引;
匹配列字首,例如有乙個索引是 user_name,那麼查詢 where user_name like "james%" 可以用上該索引;
範圍匹配,由於b-tree是有順序的,因此可以進行範圍查詢,例如有乙個索引是 user_id,那麼查詢 where user_id between 1 and 10 可以用上該索引;
精確匹配一列並且範圍匹配另一列,這就是把第一條和上一條結合起來;
只訪問索引的查詢,這種一般叫做「覆蓋索引」,意思就是要查詢的資料,都在索引裡,這樣就不用去查詢資料行,而可以直接返回結果。
但同時注意,b-tree索引也有缺點,那就是遵循最左原則:必須從左往右,而且必須是連續的,不能跳過任何一列,否則就用不上索引;此外, 範圍查詢之後的查詢,業務髮用上索引,也就是說,如果有乙個索引 (a, b, c),我們的查詢是 where a = 'a' and b like 'j%' and c = c, 索引無法用上 c,只能用上 (a, b) 這一部分。hash索引。hash索引基於雜湊表來實現,因此只有精確匹配索引所有列的查詢才能有效。由於是使用雜湊表,因此雜湊索引的結構十分緊湊, 查詢速度非常快,但是也有缺點:雜湊索引不包含資料行中的資料,因此訪問到索引之後,必須進行資料行的查詢;
雜湊表沒有順序,因此雜湊索引無法用於排序,同時也不支援範圍查詢。
而索引設計則與業務非常相關,但是必須糾正乙個錯誤,那就是我們要先思考一下,乙個查詢能用上幾個索引?答案是乙個,當然,mysql有 引入乙個叫做 index merge 的操作,也就是說使用多個索引進行查詢,然後對結果進行集合操作得到結果,但是這通常意味著索引沒有 設計好。回到上一句開頭,我們記住,在好的索引設計的情況下,資料庫一次查詢是只使用乙個索引的。設計好乙個索引通常遵循以下原則:mysql中所有的二級索引都會把主鍵包含進去,因此不能讓主鍵太長,否則索引會變得很大。例如主鍵可以設定為自增id。
所選擇的索引列的資料,區分度(區分度的概念,例如100行資料裡,50個是true,50個是false,那麼區分度就不夠高,而如果資料 是1-100,那麼區分度就很高,也就是說,通過乙個where條件篩選出來的資料如果越多,那麼區分度越低)應該足夠高,如果是乙個 聯合索引,那麼從左到右的順序應當是區分度逐漸降低。
回到開頭的問題,什麼樣的索引是三星索引呢?這三顆星分別是什麼呢?第一顆星是如果用上了索引,就給一顆星。也就是說,如果有多個查詢條件,把有索引的條件放前面。
第二顆星是如果如果索引中的資料順序和查詢中的排列順序一致,那麼就給第二顆星,也就是說,如果order by中的條件不在索引裡,那麼就不符合條件。
第三顆星是使用「覆蓋索引」,也就是說,如果如果要查詢的資料,都在索引裡,那麼就給第三顆星。因為這樣不需要去訪問資料行, 從而可以加快訪問速度。
通常來說,第三顆星比較難獲得,因為一般業務需要的資料各式各樣,不可能把所有資料都加到索引裡。但是第一和第二顆星星還是可以爭取 一下的。
查詢結合上面的索引設計,資料庫查詢也有一些常見的優化規則:查詢條件中不使用表示式,而應該使用常量。例如,應該使用 where a = 1 而不是 where a +1 = 5。
不查詢不必要的資料,如有可能,剛好查詢索引中的資料。那麼就不用多傳輸不必要的資料。使用orm的同學請注意,orm通常會把所有 資料都查詢出來,這樣才例項化物件。
避免多個範圍條件,這樣產生的資料量可能會很大,因此也就需要更多的時間來處理。使用盡可能精確的條件來進行查詢。
硬體優化
除了軟體上的優化,如果效能仍然不夠,那麼就需要提公升硬體效能了,這個就不在我們這一篇中來講述了。
總結這一篇中我們總結了資料庫(mysql)中進行優化的步驟和注意點,首先我們介紹了步驟,然後介紹了索引的型別,如何設計索引,如何 使用索引,設計出高效高效能的查詢。
mysql高效能指南 MySQL效能優化指南
1 定期分析表和檢查表 分析表的語法如下 analyze local no write to binlog table tb1 name tbl name 以上語句用於分析和儲存表的關鍵字分布,分析的結果將可以使得系統得到準確的統計資訊,使得sql能夠生成正確的執行計畫。如果使用者感覺實際執行計畫並...
高效能mysql 樹 高效能mysql精要
1 explain 中 extra using index 表示覆蓋索引,sql優化中最好能使用覆蓋索引,否則 二級索引 需要回表查詢。所謂覆蓋索引,是指要查詢的列正好是索引,而條件也是這個索引之一 2 where 語句中 條件等於主鍵的 在核心索引層完成,條件等於非索引的,在服務層完成 3 讀索引...
mysql高效能索引 mysql高效能索引( )
在開發中,我們知道大多數應用的瓶頸在於sql語句的執行時耗,在這裡並不討論sql語句的安全,僅僅討論高效能sql語句,而與高效能sql語句緊密相連的就是傳說中的 索引。索引 一種工作在儲存引擎端的用於快速找到記錄的一種資料結構。mysql使用索引的方式是 先找到索引的值,再根據索引的值找到資料行。索...