mysql優化

螞蟻style發表於2020-08-17

MySQL常見效能瓶頸

  CPU:CPU在飽和的時候一般發生在資料裝入記憶體或從磁碟上讀取資料的時候

  硬體:top, free, iostat和vmstat等命令來檢視系統效能狀態

  I/O:磁碟I/O瓶頸發生裝入資料遠大於記憶體容量的時候

  SQL:程式中SQL語句問題,Explain檢視執行計劃。

Explain簡介

  EXPLAIN 命令是檢視查詢優化器如何決定執行查詢的主要方法,MYSQL會在查詢上設定一個標記,當執行查詢時,這個標記會使其返回關於在執行計劃中每一步的資訊,從而可以從分析結果中找到查詢語句或是表結構的效能瓶頸
Explain能幹什麼?

  1:分析出表的執行順序

  2:資料讀取操作的操作型別

  3:哪些索引可以使用

  4:哪些索引被實際使用

  5:表之間的引用

EXPLAIN結果引數含義:id
  樣例:explain select * from tbl_dept;
mysql優化

 1.id:  id代表執行select子句或操作表的順序,id分別有三種不同的執行結果
id相同,執行順序由上至下
mysql優化

 2.id不同,如果是子查詢,id的序號會遞增,id值越大,優先順序越高,越先被執行
mysql優化

 3. id相同和不同,同時存在,遵從優先順序高的優先執行,優先順序相同的按照由上至下的順序執行

mysql優化

EXPLAIN結果引數含義:select_type
  查詢的型別,主要用於區別普通查詢,聯合查詢,子查詢等複雜查詢
  SIMPLE:簡單的select查詢,查詢中不包含子查詢或union查詢

mysql優化

   PRIMARY/UNION: PRIMARY:查詢中最外層的SELECT(如兩表做UNION或者存在子查詢的外層的表操作為PRIMARY,內層的操作為UNION)

   SUBQUERY: 在select 或where 列表中包含了子查詢,子查詢中首個SELECT(如果有多個子查詢存在)

 mysql優化

 EXPLAIN結果引數含義:type

  查詢型別從最好到最差依次是:system>const>eq_ref>ref>range>index>All,    一般情況下,得至少保證達到range級別,最好能達到ref

  eq_ref:唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配,常見於主鍵或唯一索引掃描
  ref:非唯一性索引掃描,返回匹配某個單獨值的行,它可能會找到多個符合條件的行,所以他應該屬於查詢和掃描的混合體
  range:只檢索給定範圍的行,使用一個索引來選擇行,如where語句中出現了between,<,>,in等查詢,這種範圍掃描索引比全表掃描要好,因為它只需要開始於索引的某一點,而結束於另一點,不用掃描全部索引。
  index:index型別只遍歷索引樹,這通常比All快,因為索引檔案通常比資料檔案小,index是從索引中讀取,all從硬碟中讀取
  all:全表掃描,是最差的一種查詢型別

EXPLAIN結果引數含義:possibles_keys

  顯示可能應用在這張表中的索引,一個或多個,查詢到的索引不一定是真正被用到的.
EXPLAIN結果引數含義:key

  實際使用的索引,如果為null,則沒有使用索引,因此會出現possible_keys列有可能被用到的索引,但是key列為null,表示實際沒用索引。
EXPLAIN結果引數含義:key_len

  表示索引中使用的位元組數,而通過該列計算查詢中使用的 索引長度,在不損失精確性的情況下,長度越短越好,key_len顯示的值為索引欄位的最大可能長度,並非實際使用長度,即,key_len是根據表定義計算而得麼不是通過表內檢索出的
EXPLAIN結果引數含義:ref

  顯示索引的哪一列被使用了,如果可能的話是一個常數,哪些列或常量被用於查詢索引列上的值
EXPLAIN結果引數含義:rows

  根據表統計資訊及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數

EXPLAIN結果引數含義:Extra 

  不適合在其他列顯示的額外資訊

  Using temporary :使用了臨時表儲存中間結果,mysql在對查詢結果排序時使用臨時表,常見於order by和分組查詢group by
  Using index:表示相應的select操作中使用了覆蓋索引(Covering Index),避免訪問了表的資料行,效率不錯。如果同時出現using where,表明索引被用來執行索引鍵值的查詢;如果沒有同時出現using where,表明索引用來讀取資料而非執行查詢動作。 其中的覆蓋索引含義是所查詢的列是和建立的索引欄位和個數是一一對應的
  Using where:表明使用了where過濾
  Using join buffer:表明使用了連線快取,如在查詢的時候會有多次join,則可能會產生臨時表
  impossible where:表示where子句的值總是false,不能用來獲取任何元祖。如下例:

    select * from t1 where id='1' and id='2';
  select tables optimized away:在沒有GROUPBY子句的情況下,基於索引優化MIN/MAX操作或者對於MyISAM儲存引擎優化 ,COUNT(*)操作,不必等到執行階段再進行計算,查詢執行計劃生成的階段即完成優化。

  distinct:優化distinct操作,在找到第一匹配的元組後即停止找同樣值的動作,即一旦MySQL找到了與行相聯合匹配的行,就不再搜尋了。

索引介紹

  索引(Index) 是幫助MySQL高效獲取資料的資料結構

  索引為什麼是一種資料結構,它又是怎麼提高查詢的速度?我們拿最常用的二叉樹來分析索引的工作原理。看下面的圖片:  mysql優化

 建立索引的優勢
      1 提高資料的檢索速度,降低資料庫IO成本:使用索引的意義就是通過縮小表中需要查詢的記錄的數目從而加快搜尋的速度。
      2 降低資料排序的成本,降低CPU消耗:索引之所以查的快,是因為先將資料排好序,若該欄位正好需要排序,則真好降低了排序的成本。

建立索引的劣勢
        1 佔用儲存空間:索引實際上也是一張表,記錄了主鍵與索引欄位,一般以索引檔案的形式儲存在磁碟上。
        2 降低更新表的速度:表的資料發生了變化,對應的索引也需要一起變更,從而減低的更新速度。否則索引指向的物理資料可能不對,這也是索引失效的原因之一。
        3 優質索引建立難:索引的建立並非一日之功,也並非一直不變。需要頻繁根據使用者的行為和具體的業務邏輯去建立最佳的索引。
常見索引型別有哪些?

  普通索引:普通索引(由關鍵字KEY或INDEX定義的索引)的唯一任務是加快對資料的訪問速度。因此,應該只為那些最經常出現在查詢條件(WHERE column = …)或排序條件(ORDER BY column)中的資料列建立索引。只要有可能,就應該選擇一個資料最整齊、最緊湊的資料列(如一個整數型別的資料列)來建立索引。

  唯一索引:唯一性索引的值是唯一的,可以更快速的通過該索引來確定某條記錄。

  主鍵索引:是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值

  組合索引:指多個欄位上建立的索引,只有在查詢條件中使用了建立索引時的第一個欄位,索引才會被使用。使用組合索引時遵循最左字首集合,比如說,INDEX(A, B, C)可以當做A或(A, B)的索引來使用,但不能當做B、C或(B, C)的索引來使用

  全文索引(倒排文件技術): 主要用來查詢文字中的關鍵字,而不是直接與索引中的值相比較。fulltext索引跟其它索引大不相同,它更像是一個搜尋引擎,而不是簡單的where語句的引數匹配。fulltext索引配合match against操作使用,而不是一般的where語句加like。它可以在create table,alter table ,create index使用,不過目前只有char、varchar,text 列上可以建立全文索引。值得一提的是,在資料量較大時候,現將資料放入一個沒有全域性索引的表中,然後再用CREATE index建立fulltext索引,要比先為一張表建立fulltext然後再將資料寫入的速度快很多。

資料庫索引的設計原則:

  1.選擇唯一性索引
例如,學生表中學號是具有唯一性的欄位。為該欄位建立唯一性索引可以很快的確定某個學生的資訊。如果使用姓名的話,可能存在同名現象,從而降低查詢速度。

  2.為經常需要排序、分組和聯合操作的欄位建立索引

   經常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的欄位,排序操作會浪費很多時間。如果為其建立索引,可以有效地避免排序操作。

  3.為常作為查詢條件的欄位建立索引
   如果某個欄位經常用來做查詢條件,那麼該欄位的查詢速度會影響整個表的查詢速度。因此,為這樣的欄位建立索引,可以提高整個表的查詢速度

  4.限制索引的數目
      索引的數目不是越多越好。每個索引都需要佔用磁碟空間,索引越多,需要的磁碟空間就越大。修改表時,對索引的重構和更新很麻煩。越多的索引,會使更新表變得很浪費時間。
  5.儘量使用資料量少的索引
   如果索引的值很長,那麼查詢的速度會受到影響。例如,對一個CHAR(100)型別的欄位進行全文,檢索需要的時間肯定要比對CHAR(10)型別的欄位需要的時間要多。
  6.儘量使用字首來索引
   如果索引欄位的值很長,最好使用值的字首來索引。例如,TEXT和BLOG型別的欄位,進行全文檢索會很浪費時間。如果只檢索欄位的前面的若干個字元,這樣可以提高檢索速度
  7.刪除不再使用或者很少使用的索引
      表中的資料被大量更新,或者資料的使用方式被改變後,原有的一些索引可能不再需要。應當定期找出這些索引,將它們刪除,從而減少索引對更新操作的影響。
  8.小表不應建立索引,包含大量的列並且不需要搜尋非空值的時候可以考慮不建索引  
  9.儘量不要對資料庫中某個含有大量重複的值的欄位建立索引。
      對於一個ENUM型別的欄位來說,出現大量重複值是很有可能的情況,例如“sex”欄位,在這樣的欄位上建立索引將不會有什麼幫助;相反,還有可能降低資料庫的效能。
索引中需要注意的事項

  1.索引不會包含有null值的列
        只要列中包含有null值都將不會被包含在索引中,複合索引中只要有一列含有null值,那麼這一列對於此複合索引就是無效的。所以我們在資料庫設計時不要讓欄位的預設值為null。

  2.以%開頭的LIKE查詢不能使用索引
       explain select deptName,remark,createDate from dept where deptName like'%2' and remark = 'test'and createDate ='2018-07-22'; type index
  SELECT * FROM `houdunwang` WHERE `uname` LIKE'金蝶%' -- 走索引
  SELECT * FROM `houdunwang` WHERE `uname` LIKE "%金蝶%" -- 不走索引

  3.資料型別出現隱式轉換時也不能使用索引
       explain select deptName,remark,createDate from dept where deptName =2 and remark = 'test'and createDate ='2018-07-22'; type index

  4.複合索引時 不符合最左匹配原則
  增加聯合索引 ALTER TABLE dept ADD INDEX index_all (`deptName`,`remark`,`createDate`);
     explain select deptName,remark,createDate from dept where remark = 'test'and createDate ='2018-07-22'; type index

  5. 用or分隔開的條件,如果or前的條件中的列有索引,後面的列中沒有索引,那麼涉及到的索引都不會使用到
  增加聯合索引 ALTER TABLE dept ADD INDEX index_all (`deptName`,`remark`,`createDate`);
     explain select deptName,remark,createDate from dept where deptName ='2' and remark = 'test'and createDate ='2018-07-22' or salary =200; type ALL

  6.order by 欄位混合使用DESC ASC 不會使用索引
     select * from table order by key1 desc,key2 asc (儘量不要出現這種混合排序)

  7.Where條件過濾的關鍵字和Order by中所使用的不同 不會使用索引
     select * from table where key2 = ? order by key1 (order by 出現的關鍵字 儘量 在where條件中也出現)

  8.多表連線的時候 join on(a.id=b.id2) 連線外來鍵id、id2 必須加索引。MySQL規定作為外來鍵的欄位必須有索引 也是為了讓我們表連線的時候 用到索引

  9.  SELECT `sname` FROM `stu` WHERE `age`+10=30;-- 不會使用索引,因為所有索引列參與了計算
  10.  SELECT `sname` FROM `stu` WHERE LEFT(`date`,4) <1990; -- 不會使用索引,因為使用了函式運算
  11.字串與數字比較不使用索引;
      EXPLAIN SELECT * FROM `a` WHERE `a`="1" -- 走索引
      EXPLAIN SELECT * FROM `a` WHERE `a`=1 -- 不走索引,同樣也是使用了函式運算

總結:

  索引的建立必須慎重,對每個索引的必要性都應該經過仔細分析,要有建立的依據。因為太多的索引與不充分、不正確的索引對效能都毫無益處:在表上建立的每個索引都會增加儲存開銷,索引對於插入、刪除、更新操作也會增加處理上的開銷。另外,過多的複合索引,在有單欄位索引的情況下,一般都是沒有存在價值的;相反,還會降低資料增加刪除時的效能,特別是對頻繁更新的表來說,負面影響更大.

相關文章