淺談MySQL的索引(2)

????上一篇我們從索引的存儲結構分析,說到了B Tree索引、Hash索引、FULLTEXT全文索引。這一期,我們在從其他層次學習洗索引。


一、前期回顧

  • 從索引存儲結構劃分:B Tree索引、Hash索引、FULLTEXT全文索引以及R Tree索引

  • 從應用層次劃分:普通索引、唯一索引、主鍵索引、復合索引

  • 從鍵值劃分:主鍵、輔助

  • 從數據存儲以及索引邏輯關系劃分:聚集索引、非聚集索引


  • 二、索引的分類


    2.1、普通索引

    ????????普通索引既我們平時常用的索引,默認使用的是BTree。

    ALTER?TABLE?`user`ADD?INDEX?`index_userNm`?(`username`)?USING?BTREE?COMMENT?'用戶名索引';--?或者ALTER?TABLE?`user`ADD?INDEX?`index_userNm`?(`username`);

    2.2、唯一索引

    ????????與普通索引類似,不同的點在于:索引的值必須唯一,允許有空值。換句話說?某種程度上說的就是表中索引鎖標記的唯一列。

    ALTER?TABLE?`user`?ADD?UNIQUE?INDEX?`index_un_id`(`id`);

    主鍵索引

    ????????與唯一索引的區別就是索引標記的列不允許有空值,換句話說就是主鍵列上加的索引。

    ALTER?TABLE?`user`?ADD?PRIMARY?KEY?(`id`);

    2.3、復合索引

    ????????又名聯合索引,也是我們比較常用的索引類型之一。在數據表的2列或>2列共同組成的索引。而上面我們說的普通索引、唯一索引、主鍵索引又叫單一索引。顧名思義是指索引列只有一列,而用戶可以在多個列上建立索引,這種索引就叫復合索引,也叫組合索引、聯合索引,復合索引可以代替多個單一索引,相遇多個單一索引,復合索引所需的開銷更小。


    在這里復合索引還有個小小的區分:窄索引、寬索引

    • 窄索引:指索引列為1-2列的索引

    • 寬索引:指索引列超過2列的索引

    ??索引設計原則:能用窄索引不用寬索引,因為窄索引往往比組合索引更有效


    ? ?值得我們重點關注的是:

  • 需要加索引的字段,要在where條件中。

  • 數據量少的字段不需要加索引。最窄的字段放在鍵的左邊。

  • 如果where條件中是OR關系,必須所有的or條件都必須是獨立索引,否則加索引不起作用。見:mysql關于or的索引問題

  • 左匹配原則。

  • 只要列中包含有NULL值都將不會被包含在索引中,復合索引中只要有一列含有NULL值,那么這一列對于此復合索引就是無效的。所以我們在數據庫設計時不要讓字段的默認值為NULL。


  • eg:

    假設某個表有一個聯合索引(c1,c2,c3,c4)以下選項哪些字段使用了該索引:
    A where c1=x and c2=x and c4>x and c3=x
    B where c1=x and c2=x and c4=x order by c3
    C where c1=x and c4= x group by c3,c2
    D where c1=? and c5=? order by c2,c3
    E where c1=? and c2=? and c5=? order by c2,c3


    接下來借用上面的例子,我們求證一下:

  • 首先創建表:

  • CREATE?TABLE?t(??c1?CHAR(1)?not?null,??c2?CHAR(1)?not?null,??c3?CHAR(1)?not?null,??c4?CHAR(1)?not?null,??c5?CHAR(1)?not?null)ENGINE?myisam?CHARSET?UTF8;

  • 創建索引:

  • alter?table?t?add?index?c1234(c1,c2,c3,c4);

  • 隨機搞兩條數據:

  • insert?into?t?VALUES('1','1','1','1','1'),('2','2','2','2','2')

  • 使用MySql Explain開始分析題目結果:

  • A 選項:where c1=x and c2=x and c4>x and c3=x



    說明下:UTF-8 編碼,一個索引的長度為3,如上圖我們可以看到,c1,c2,c3,c4均使用到了該索引。

    但是如果我們將查詢條件調整下或者去掉一個,索引又是怎么使用的呢:





    由上面4個圖可以看出,我們分別調整了各個列的位置,使用>和使用>的位置,發現索引都是正常使用的,所以可以得出:

  • 使用“<” / “>”并不影響索引的選擇

  • where條件和創建索引的列保持一致時,條件的位置(順序)并不影響索引的選擇。


  • 但是,如果我們對A組where條件做些調整呢?




    當我們刪除分別其中一個條件c1、c2、c3后,發現使用索引的個數也發生了變化。得出結論:

  • 當使用復合索引時,沒有使用第一個復合索引,不觸發索引的使用

  • 使用復核索引時,索引的選擇與where的條件順序和索引建立時的順序是否一致存在關系,當順序中斷時,后續的索引列將不被選擇。


  • 如果我們對A組where條件做些調整呢?








    當我們使用or,或者like時,通過上面4張圖可以清醒的得出:

  • 當使用or時,不會使用索引

  • 當條件順序與索引創建順序一致,且使用?“like”?/?“like%”時,索引可以正常被選中

  • 當條件順序與索引創建順序一致,且使用 “%like%”,索引無法被選中

  • 當條件順序與索引創建順序不一致時,且第一個條件不是索引創建時的首列,則無法選中索引


  • B選項:where c1=x and c2=x and c4=x order by c3



    通過上圖可以發現,key_len長度說明c1,c2字段用到了該索引,Extra顯示并沒有使用臨時表進行排序,說明排序是使用了索引的,但并沒有計算在key_len值中,也沒有起到連接c4的作用,說明索引到c3這里是斷掉的。

    排序其實是利用聯合索引直接完成了的,即:使用了c1234聯合索引,就已經使得c1下c2,c2下c3,c3下c4是有序的了,所以實際是排序利用了索引,c3字段并沒有使用該索引。


    C選項:where c1=x and c4= x group by c3,c2



    通過上面兩圖,能看出使用group by 一般先生成臨時文件,再進行排序,但是字段順序為c2,c3時,并沒有用臨時表進行排序,而是利用索引排序好的;當group by字段為c3,c2時,由于與索引字段順序不一致,所以分組和排序并沒有利用到索引。


    D選項:where c1=? and c5=? order by c2,c3


    通過此圖可以看出 order by 和group by 類似,字段順序與索引一致時,會使用索引排序;字段順序與索引不一致時,不使用索引。


    E選項:where c1=? and c2=? and c5=? order by c2,c3


    其實選項E的結果分析在上述ABCD的結果中都分析過了,這里只有c1,c2字段使用了該索引。

    綜上所述問題答案:

    ????A:四個字段均使用了該索引

    ????B:c1,c2字段使用了該索引

    ????C:c1字段使用該索引

    ????D:c1字段使用該索引

    ????E:c1,c2字段使用了該索引

    三、小結:

  • 索引的最左原則(左前綴原則),如(c1,c2,c3,c4....cN)的聯合索引,

  • where 條件按照索引建立的字段順序來使用(不代表and條件必須按照順序來寫),

  • 如果中間某列沒有條件,或使用like會導致后面的列不能使用索引。

  • 索引也能用于分組和排序,分組要先排序,在計算平均值等等。所以在分組和排序中,如果字段順序可以按照索引的字段順序,即可利用索引的有序特性。


  • 不知不覺寫到這又有 2.5k 多字了,本期我們就寫到這里,下期我們繼續

    探討索引。

    …………………………………分割線……………………………

    不積跬步,無以至千里;不積小流,無以成江海。

    關注我,每天分享一些小知識點。分享自己的小心得,包含但不限于初、中、高級面試題呦!!!

    我都墨跡這么半天了 ,你不點關注,不點贊,不收藏,還不轉發,你想干啥!!!

    最后編輯于
    ?著作權歸作者所有,轉載或內容合作請聯系作者
    平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

    推薦閱讀更多精彩內容