1. 程式人生 > >mysql效能優化之建立高效能索引

mysql效能優化之建立高效能索引

索引對效能的優化十分重要,是對查詢優化最有效的手段。
一、索引的型別
索引是在儲存引擎層而不是服務層實現的。不同儲存引擎的索引工作方式不一樣。
1、B-Tree索引
它使用的是B-Tree資料結構來儲存資料。b-tree索引能夠加快訪問資料的速度,因為儲存引擎不在需要進行全表掃描來獲取需要的資料,取而代之的是從索引的根節點開始進行搜尋。根節點的槽中存放了指向子節點的指標,儲存引擎根據這些指標向下查詢。通過比較節點頁的值和要查詢的值就可以找到合適的指標進入下層子節點,這些指標實際上定義了子節點頁中值的上限和下限。
索引對多個值進行排序的依據是create table語句中定義索引時列的順序。

  • 全值匹配。和索引中的所有列進行匹配
  • 匹配最左字首。只使用索引的第一列
  • 匹配列字首。只匹配某一列的值開頭部分。
  • 匹配範圍值。
  • 精確匹配某一列並範圍匹配另一列
  • 只訪問索引的查詢
    1.1 B-Tree索引的限制
  • 如果不是按照索引的最左列開始查詢,則無法使用索引。
  • 不能跳過索引中的列。
  • 如果查詢有某個列的範圍查詢,則其右邊所有列都無法使用索引優化查詢。
    到這裡我們發現,索引列的順序是多麼重要,這些限制和索引列的順序有關。在優化效能的時候可能需要使用相同的列但順序不同的索引來滿足不同型別的查詢需求。
    二、雜湊索引
    雜湊索引(hash index)基於雜湊表實現,只有精確匹配索引所有列的查詢才能有效。對每一行索引列都會計算一個HashCode。雜湊碼是一個較小的值,雜湊索引將所有的雜湊碼儲存在索引中,同時在雜湊表中儲存指向每個資料行的指標。
    雜湊索引也有它 的限制
  • 雜湊索引只包含雜湊值和行指標,而不儲存欄位值。
  • 雜湊索引資料並不按照索引值順序儲存,所以無法用於排序
  • 雜湊索引也不支援部分索引列匹配查詢,因為雜湊索引始終使用索引列的全部內容計算雜湊值。
  • 雜湊索引只支援等值比較查詢,包括=、IN()、<=>也不支援任何範圍查詢。
  • 訪問雜湊索引的資料非常快,除非有很多雜湊衝突(不同的索引列值卻有相同的雜湊值)。當出現雜湊衝突時候,儲存引擎必須遍歷連結串列中所有的行指標,逐行進行比較,直到找到所有符合條件的行。
  • 如果雜湊衝突很多的話,一些索引維護操作的代價也會很高。
    三、索引的優點
    索引可以讓伺服器快速的定位到表的指定位置。但這並不是索引唯一的作用。最常見的b-tree索引,按照順序儲存資料,所以mysql可以用來做order by和 group by操作。
    索引大大減少了伺服器需要掃描的資料量。索引可以幫助伺服器避免順序和臨時表。索引可以將隨機I/O變為順序I/O。
    對於非常小的表,大部分情況下簡單的全表掃描更高效。對於中到大型的表,索引就非常有效。但對於特大型的表,建立和使用索引的代價將隨之而來。
    四、高效能索引策略
  • 獨立的列。
    是指索引列不能是表示式的一部分,也不是函式的引數。例如:select xxx from xxx where id + 1 = 5;mysql無法自動解析這個方程,我們應該簡化where條件的習慣,始終將索引列單獨放在比較符號的一側。
  • 字首索引和索引選擇性。
    有時候需要索引很長的字元列,這會讓索引變得大且慢,我們要選擇足夠長的字首以保證較高的選擇性,同時又不能太長(以便節約空間)字首應該足夠長,以使得字首索引的選擇性接近於索引整個列。找到合適的字首長度後通過alter table test add key(city(7));建立索引
  • 多列索引
    在多個列上建立獨立的單列索引並不能提高mysql的查詢特性。mysql5.0和更新版本引入了一種叫做索引合併的策略,一定程度上可以使用表上的多個單列索引來定位指定的行。可以通過引數optimizer_switch來關閉索引合併功能。也可以使用ignore index提示讓優化器忽略某些索引。
  • 選擇合適的索引列順序
    當不考慮排序和分組時,將選擇性最高的列放到索引最前列。這時候索引只是優化where條件的查詢。
  • 聚簇索引
    聚簇索引不是一種索引型別,而是一種資料儲存方式。Innodb的聚簇索引實際上在同一個結構中儲存了B-Tree索引和資料行。它的資料行實際上在同一個結構中儲存了B-Tree索引和資料行。
  • 覆蓋索引
    通常大家會根據where條件來建立合適的索引,不過這只是索引優化的一個方面。如果一個索引包含或者說覆蓋所有要查詢的欄位的值,我們就稱之為覆蓋索引。
    五、總結
    在選擇索引和編寫利用這些索引的查詢時,有三個原則始終牢記
    • 單行訪問是很慢的
      可以使用索引建立位置引用提升效率
    • 按順序訪問範圍資料是很快的
      1、順序I/O不需要多次磁碟尋道,2、若果按照順序索引,那麼就不需要額外的排序操作,並且group by查詢也無需再做排序和行按組進行聚合計算
    • 索引覆蓋查詢很快。
      如果一個索引包含了查詢需要的所有列,那麼儲存引擎就不要回表查詢行。這避免了大量的單行訪問。

六、如何判斷一個系統建立的索引是合理的?
按照響應時間來對查詢進行分析。找到那些消耗時間最長的查詢或者那些給伺服器帶來最大壓力的查詢,然後檢查這些查詢的schema 、sql和索引結構,判斷是否掃描了太多的行。

七、應該選擇那些列作為索引?
- select update delete 語句的where從句中的列
- 包含在order by group by distincr中的欄位聯合索引
- 多表join的關聯列
索引列的順序又應該是怎麼樣的呢
索引按照從左向右的順序執行
- 區分度最高的列放在聯合索引的最左側
- 儘量把欄位長度小的列放在聯合索引的最左側
- 使用最頻繁的列放在聯合索引的左側
避免建立冗餘索引和重複索引比如:
index(a、b、c)、index(a、b)、index(a)
primary key(id)、index(id)、unique index(id);
對於頻繁查詢優先考慮使用覆蓋索引(包含所有查詢欄位的索引)可以避免innodb表進行索引的二次查詢、可以把隨機I/O變為順序IO加快查詢效率
儘量避免使用外來鍵
不建議使用外來鍵約束、但一定在表與表之間的關聯鍵上建立索引、外來鍵會影響父表和子表的寫操作從而降低效能