MySQL 筆記 - 索引優化

寫在前面

這篇文章是《高性能 MySQL》第五章的讀書筆記以及總結~旨在幫助我本身梳理並總結書中的知識點和內容~同時也爲一些懶得看書的小夥伴提供一個提取好的知識點~以爲水的朋友煩請關閉喲數據庫

巧妙的使用 Explain

看一條 SQL 語句的性能,可使用 explain 關鍵字查看語句性能,這裏說一下其中的 type 字段的部分含義,服務器

  • all,即全表掃描,說明這個 SQL 語句沒有使用到索引,有多是表自己沒有建立索引,也多是由於 SQL 語句致使沒有使用索引
  • range,說明使用的是有範圍的索引掃描,性能優於 index
  • index,這裏說明使用了索引,這種狀況下,若是 extra 列中的值爲 Using index,這種狀況是索引覆蓋,索引覆蓋的意思是,咱們想要查詢的數據,索引中已經都存在啦,這種狀況下就不須要再回表取數據了
  • ref,說明條件列使用了索引,可是不是主鍵和 unique,因此這裏即便使用了索引,索引值不惟一,有重複的狀況
  • eq_ref,相對於 ref 來講就是使用的是惟一索引,對於每一個索引鍵值,只有惟一的一條匹配記錄
  • const/system,單表中最多隻有一條匹配行,查詢起來很是迅速,因此這個匹配行中的其餘列中的值能夠被優化器在當前查詢中當作常量來處理。例如根據主鍵或者惟一索引進行的查詢
  • index_merge,說明使用了 MySQL 的索引合併的優化方法,當使用合併索引的時候,就須要檢查一下咱們所建立的索引是否爲多個單列索引

如何有效的優化索引

使用索引的時候,索引必須做爲獨立的列出現

做爲獨立的列的意思是,索引不能做爲表達式的一部分,也不能做爲函數的參數出現,不然索引會失效,緣由是 MySQL 沒法自動解析表達式以及參數,因此也就沒法使用索引了,索引失效還有如下幾種狀況:函數

  • 條件中使用 is null 或者 is not null 會致使索引失效,緣由是索引中不會存儲 null
  • 使用 %like,由於 MySQL 是左匹配,使用模糊查詢時若是以%開頭會致使全表查詢
  • 使用多列索引的時候,若是索引順序不是創建索引的順序,或者跳過第一個索引直接使用後面的索引,也會致使索引失敗,緣由依然是 MySQL 是左匹配~
  • 條件中包含or時,只有全部列都是單獨索引時纔會使用索引

如何建立有效的索引

  • 若是須要索引很長的字符串,此時須要考慮前綴索引
    • 前綴索引即選擇所需字符串的一部分前綴做爲索引,這時候,須要引入一個概念叫作索引選擇性,索引選擇性是指不重複的索引值與數據表的記錄總數的比值,能夠看出索引選擇性越高則查詢效率越高,當索引選擇性爲1時,效率是最高的,可是在這種場景下,很明顯索引選擇性爲1的話咱們會付出比較高的代價,索引會很大,這時候咱們就須要選擇字符串的一部分前綴做爲索引,一般狀況下一列的前綴做爲索引選擇性也是很高的
    • 如何選擇前綴
      • 計算該列完整列的選擇性,使得前綴選擇性接近於完整列的選擇性
  • 使用多列索引
    • 儘可能不要爲多列上建立單列索引,由於這樣的狀況下最多隻能使用一星索引,這樣的話,不如去建立一個全覆蓋索引,在多列上建立單列索引大部分狀況下並不能提升 MySQL 的查詢性能,MySQL 5.0 中引入了合併索引,在必定程度上能夠表內多個單列索引來定位指定的結果,可是 5.0 之前的版本,若是 where 中的多個條件是基於多個單列索引,那麼 MySQL 是沒法使用這些索引的,這種狀況下,還不如使用 union
  • 選擇合適的索引列順序
    • 經驗是將選擇性最高的列放到索引最前列,能夠在查詢的時候過濾出更少的結果集
    • 但這樣並不老是最好的,若是考慮到 group by 或者 order by 等狀況,再好比考慮到一些特別場景下的 guest 帳號等數據狀況,上面的經驗法則可能就不是最適用的
  • 覆蓋索引
    • 所謂覆蓋索引就是指索引中包含了查詢中的全部字段,這種狀況下就不須要再進行回表查詢了
    • MySQL 中只能使用 B-Tree 索引作覆蓋索引,由於哈希索引等都不存儲索引的列的值,覆蓋索引對於 MyISAM 和 InnoDB 都很是有效,能夠減小系統調用和數據拷貝等時間
    • Tips:減小 select * 操做
  • 使用索引掃描來作排序
    • MySQL 生成有序的結果有兩種方法:經過排序操做,或者按照索引順序掃描;使用排序操做須要佔用大量的 CPU 和內存資源,而使用 index 性能是很好的,因此,當咱們查詢有序結果時,儘可能使用索引順序掃描來生成有序結果集
    • 怎樣保證使用索引順序掃描:
      • 索引列順序和 ORDER BY 順序一致
      • 全部列的排序方向一致
      • 若是關聯多表,那麼只有當 ORDER BY 子句引用的字段所有爲第一張表時,才能使用索引作排序,限制依然是須要知足索引的最左前綴要求
  • 壓縮索引
    • 上一篇將索引結構的文章提到了,MyISAM 中使用了前綴壓縮技術,會減小索引的大小,能夠在內存中存儲更多的索引,這部分優化默認也是隻針對字符串的,可是能夠自定義對整數作壓縮
    • 這個優化在必定狀況下性能比較好,可是對於某些狀況可能會致使更慢,由於前綴壓縮決定了每一個關鍵字都必須依賴於前面的值,因此沒法使用二分查找等,只能順序掃描,因此若是查找的是逆序那麼性能可能不佳
  • 減小重複、冗餘以及未使用的索引
    • MySQL 的惟一限制和主鍵限制都是經過索引實現的,因此不須要在同一列上增長主鍵、惟一限制再建立索引,這樣是重複索引
    • 再舉個例子,若是已經建立了索引(A,B),那麼再建立索引(A)的話,就屬於重複索引,由於 MySQL 索引是最左前綴,因此索引(A,B)自己就可使用索引(A),可是建立索引(B)的話不屬於重複索引
    • 儘可能減小新增索引,而應該擴展已有的索引,由於新增索引可能會致使 INSERT、UPDATE、DELETE 等操做更慢
    • 能夠考慮刪除沒有使用到的索引,定位未使用的索引,有兩個辦法,在 Percona Server 或者 MariaDB 中打開 userstates 服務器變量,而後等服務器運行一段時間後,經過查詢 INFORMATION_SCHEMA.INDEX_STATISTICS 就能夠查詢到每一個索引的使用頻率
  • 索引和鎖
    • 以前講索引結構的時候說過,InnoDB 支持行鎖和表鎖,默認使用行鎖,而 MyISAM 使用的是表鎖,因此使用索引可讓查詢鎖定更少的行,這樣也會提高查詢的性能,若是查詢中鎖定了1000行,但實際只是用了100行,那麼在 5.1 以前都須要提交事務以後才能釋放這些鎖,5.1 以後能夠在服務器端過濾掉行以後就釋放鎖,不過依然會致使一些鎖衝突
  • 減小索引和數據碎片
    • 首先咱們須要瞭解一下爲何會產生碎片,好比 InnoDB 刪除數據時,這一段空間就會被留空,若是一段時間內大量刪除數據,就會致使留空的空間比實際的存儲空間還要大,這時候若是進行新的插入操做時,MySQL 會嘗試從新使用這部分空間,可是依然沒法完全佔用,這樣就會產生碎片
    • 產生碎片帶來的後果固然是,下降查詢性能,由於這種狀況會致使隨機磁盤訪問
    • 能夠經過 OPTIMIZE TABLE 或者從新導入數據表來整理數據

總結

數據庫的索引這部分要講的話實在是太多了~絕大部分狀況都須要結合實際狀況,若是咱們能夠更多的瞭解數據庫索引自己的一些原理,那麼對於優化會有一些幫助~巧妙地使用 explain 分析本身所寫的 SQL 語句,能夠更好的進行優化。性能

相關文章
相關標籤/搜索