如何構建高性能MySQL索引

介紹

    上一篇文章中介紹了MySQL的索引基本原理以及常見的索引種類,這邊文章的重點在於如何構建一個高性能的MySQL索引,從中你能夠學到如何分析一個索引是否是好索引,以及如何構建一個好的索引。程序員

索引誤區

多列索引

    一個索引的常見誤區是爲每一列建立一個索引,以下面建立的索引:sql

CREATE TABLE `t` (
  `c1` varchar(50) DEFAULT NULL,
  `c2` varchar(50) DEFAULT NULL,
  `c3` varchar(50) DEFAULT NULL,
  KEY `c1` (`c1`),
  KEY `c2` (`c2`),
  KEY `c3` (`c3`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


    t表裏有三列,而且爲每列建立了一個索引。建立索引的人爲了可以快速訪問表中的任何一列,所以爲每一列添加了一個單獨的索引。在多個列上建立索引一般並不能很好的提升MySQL查詢性能,雖說MySQL 5.0以後引入了索引合併策略,能夠將多個單列索引合併成一個索引,但這並不老是有效的。同時建立多個索引的時候還會增長數據插入的成本,在插入數據的時候須要同時維護多個索引的寫入操做。微信

 

索引的計算

    看下面這條sql語句:app

select name from student where id + 1 = 5


    即便咱們在student表的id列上創建索引,上面的這條SQL語句也沒法使用索引。SQL語句中索引字段不能是表達式的一部分,也不能是函數的參數。函數

 

索引的長度以及選擇性

    儘可能不要在一個很長的列上使用索引,不然會致使索引佔用的空間很大,同時在進行數據的插入和更新的時候意味着更慢的速度。所以使用uuid列做爲索引並非一個好的選擇。從上一篇文章中咱們能夠知道,爲了加快數據的訪問索引是須要常駐內存的,假如說咱們把64位uuid做爲索引,那麼隨着表中數據量的增長索引的大小也在急劇增長。同時由於uuid並無順序性,所以在數據插入的時候都須要從根節點找到當前索引的插入位置,若是同一個節點中的索引大小達到上限,還會致使節點分裂,更加下降了插入速度。
    建立索引另一個須要考慮的是索引的選擇性,一般狀況下咱們會使用選擇性高的列做爲索引,可是也不必定一直是這樣,下一節會介紹如何權衡索引的選擇性。性能

建立高性能索引

選擇正確的索引順序

    在選擇索引的順序的時候有一個原則:將索引選擇性最高的列放在左側,同時索引的順序要與查詢索引的順序一致,而且要兼顧考慮排序和分組的須要。在一個多列B樹多列中索引的順序意味着索引首先按照最左側的列進行排序,其次是第二列。因此不管是where語句仍是order by語句都須要儘可能知足這個順序,這樣才能更好的使用索引。優化

索引的選擇性

    列的選擇性高的含義是經過這一列可以更多的過濾掉無用的數據,舉個極端的例子,若是把自增id建成索引那麼它的選擇性是最高的,由於會把無用的數據都過濾掉,只會剩下一條有效數據。咱們能夠經過下面的方式來簡單衡量某一個列的選擇性:ui

select count(distinct columnA)/count(*) as selectivity from table


當上面的數據越大的時候意味着columnA的選擇性越高。這種方式提供了一個衡量平均選擇性的辦法,可是也不必定是有效的,須要具體狀況具體分析。spa

 

前綴索引

    當遇到特別長的列,但又必需要創建索引的時候能夠考慮創建前綴索引。前綴索引的含義是把某一列的前N個字符做爲索引,建立前綴索引的方式以下:指針

alter table test add key(columnA(5));


上面這個語句就是把columnA的前5個字符建立爲前綴索引。前綴索引是一種使索引更小、更快的有效辦法。可是前綴全部有一個缺點:MySQL沒法使用前綴索引來作order by和group by,也沒法使用前綴索引作覆蓋掃描。

 

聚簇索引和非聚簇索引

聚簇索引

    聚簇索引表明一種數據的存儲方式,表示同一個結構中保存了B-Tree索引和數據行。也就是說當創建聚簇索引的時候實際的數據行存放在索引的葉子節點上。這也決定了每一個表只能有一個聚簇索引。
聚簇索引組織數據的方式以下圖所示:

    從圖中能夠看到索引的葉子節點和數據行是存放在一塊兒的,這樣的好處是能夠直接讀取到數據行。在建立表的時候若是咱們不顯式指定聚簇索引,那麼MySQL將會按照下面的邏輯來選擇聚簇索引:首先會經過主鍵列來彙集數據,若是沒有主鍵列那麼會選擇惟一的非空索引來替代。若是尚未這樣的索引那麼會隱式的建立一個主鍵列來做爲聚簇索引。
    聚簇索引優勢:
一、相關數據存放在一塊兒,檢索的時候下降IO的次數
二、數據訪問更快
三、使用覆蓋索引掃描的查詢能夠直接使用節點中的主鍵值
    在使用上面的優勢的時候聚簇索引也有必定的缺點:
一、聚簇索引將數據彙集在一塊兒限制了插入速度,插入速度比較依賴於主鍵的順序
二、更新索引的時候代價會變高
三、二級索引的訪問的時候須要查找兩次

非聚簇索引

    非聚簇索引一般被稱爲二級索引,與聚簇索引的不一樣在於,非聚簇索引的葉子節點存放的是數據的行指針或者是一個主鍵值。這樣在查找數據的時候首先定位到葉子節點上的主鍵值(或者行指針),而後經過主鍵值再到聚簇索引中查找到對應的數據。從中咱們能夠看到對於非聚簇索引的查詢須要走兩次索引。下圖是一個非聚簇索引:

    這個索引是InnoDB中的耳機索引,葉子節點中存儲的是索引和主鍵。對於MyISAM葉子節點存儲的是索引和行指針。

覆蓋索引

    若是一個索引包含或者說覆蓋全部須要查詢的字段的值,那麼就稱爲覆蓋索引。覆蓋索引能夠極大的提升查詢的效率,若是咱們的查詢中只查詢索引,而不用去回表那應該最好不過了。
    一般咱們使用explain關鍵字來查看一個查詢語句的執行計劃,經過執行計劃咱們能夠了解到查詢的細節。若是是覆蓋索引,咱們會看到執行計劃的Extra列裏有」Using Index」的信息。在查詢語句中通常咱們但願是where條件中的語句儘可能能被覆蓋,而且順序要跟索引的保持一致。還有一個須要注意的點是MySQL不能在索引中使用like操做,這樣會致使後面的索引失效。

後記

    本文主要講了幾種索引的原理以及如何構建一個高性能的索引。索引的優先是一個漸進的過程,隨着數據量和查詢語句的不一樣而發生變化,重要的是瞭解索引的原理,這樣作出正確的優化。下一篇文章中將會介紹explain關鍵字,教你如何來看執行計劃,以及如何判斷一個查詢語句是否須要優化的。

----------------------------------------------------------------

歡迎關注個人微信公衆號:yunxi-talk,分享Java乾貨,進階Java程序員必備。

相關文章
相關標籤/搜索