MySQL深入06-索引

簡介

  • 索引(也叫做鍵key)是存儲引擎用於快速找到記錄的一種數據結構;

  • 索引對於良好的性能非常關鍵,尤其是當表中的數據量越來越大時;

  • 索引優化應該是對查詢性能優化最有效的手段了,索引能夠輕易將查詢性能提高几個數量級;


索引的優點

  • 索引大大減少了服務器需要掃描的數據量:即讓服務器快速定位到表的指定位置,而不需要全表掃描;

  • 索引可以幫助服務器避免排序和臨時表:如常見的B-Tree索引,是按照順序存儲數據的,可以做order by和group by操作等;

  • 索引可以將隨機I/O變爲順序I/O:因爲索引中存儲了實際的列值,故某些查詢只使用索引就能夠完成全部查詢;


索引類型

B-Tree索引

  • 最常見的一種索引類型,所有的值都是按順序存儲的,且每一個葉子頁到根的距離相同;

  • B-Tree索引能夠加快訪問數據的速度,因爲存儲引擎不再需要進行全表掃描來獲取需要的數據,取而代之的是從索引的根節點開始進行搜索;

  • 根節點的槽中存放了指向子節點的指針,存儲引擎根據這些指針向下層查找;

  • 通過比較節點頁的值和要查找的值可以找到合適的指針進入下層子節點,這些指針實際上定義了子節點頁中值的上限和下限;

  • 最終存儲引擎要麼找到對應的值,要麼該記錄不存在;

  • B-Tree索引適用於:全鍵值、鍵值範圍或鍵前綴查找;

  • B-Tree索引的抽象表示如下:

  • wKiom1NWbTyQX1TRAAN7B2jwFco040.jpg

  • B-Tree索引的數據分佈如下:

  • wKioL1NWbYSCpgg4AATl4ORypI4240.jpg

哈希索引

  • 基於哈希表實現,只有精確匹配索引所有列的查詢纔有效;

  • 對於每一行數據,存儲引擎都會對所有的索引列計算一個哈希碼(hash code);

  • 哈希碼是一個較小的值,並且不同鍵值的行計算出來的哈希碼也不一樣;

  • 哈希索引將所有的哈希碼存儲在索引中,同時在哈希表中保存指向每個數據行的指針;

缺點

  • 只包含哈希值和行指針,而不存儲字段值,故不能使用索引中的值來避免讀取行;

  • 數據不是按照索引值順序存儲的,故不能用於排序;

  • 不支持部分索引列匹配查找;

  • 只支持等值比較查詢,包括=,IN(),<=>,也不支持任何範圍查詢;

  • 當不同的索引列卻有相同的哈希值時,就出現了哈希衝突,當在哈希衝突很多的列上建立哈希索引時,就會導致維護代價過高;

InnoDB的“自適應哈希索引(adaptive hash index)”:

  • 當InnoDB注意到某些索引值被使用得非常頻繁時,他會在內存中基於B-Tree索引之上再創建一個哈希索引;

  • 這樣就讓B-Tree索引也具有哈希索引的一些優點,比如快速的哈希查找;

  • 這是一個完全自動的、內部的行爲,用戶無法控制或者配置

空間數據索引

  • MyISAM表支持空間索引,可以用作地理數據存儲;

  • 和B-Tree索引不同,這類索引無需前綴查詢;

  • 空間索引會從所有維度來索引數據,查詢時可以有效的使用任意維度來組合查詢;

全文索引

  • 一種特殊類型的索引,它查找的是文本中的關鍵詞,而不是直接比較索引中的值;

  • 全文搜索涉及更多的細節,包括停用詞、詞幹和複數、布爾搜索等;

  • 在相同的列上同時創建全文索引和基於值的B-Tree索引不會有衝突;

  • 全文索引適用於MATCH AGAINST操作,而不是普通的WHERE條件操作;

其它索引類別:如分形樹索引,聚簇索引,覆蓋索引等


高性能的索引策略

獨立的列

  • 指索引列不能是表達式的一部分,也不能是函數的參數,否則MySQL就不會使用索引;

  • 如:select actor_id from sakila.actor where actor_id +1 = 5;

前綴索引和索引選擇性

  • 當需要索引很長的字符列時,會使索引變得大且慢,解決方式是隻索引開始的部分字符,這樣可以大大節約索引空間,從而提高索引效率,但仍需注意索引選擇性的降低;

  • 索引的選擇性是指,不重複的索引值和數據表的記錄總數的比值,範圍從0-1之間;

  • 索引的選擇性越高則查詢效率越高,因爲選擇性高的索引可以讓MySQL在查找時過濾掉更多的行;

  • 當選擇了合適長度的前綴,使得前綴索引的選擇性接近於索引整個列的選擇性時,就可以使用此前綴索引了;

多列索引

  • 在多個列上建立獨立的單列索引大部分情況下並不能提高MySQL的查詢性能;

  • 當出現服務器對多個索引做相交操作時(通常有多個AND條件),通常意味着需要一個包含所有相關列的多列索引,而不是多個獨立的單列索引;

  • 當服務器需要對多個索引做聯合操作時(通常是有個OR條件),通常需要耗費大量CPU和內存資源在算法的緩存、排序和合並操作上;

選擇合適的索引列順序

  • 正確的順序依賴於使用該索引的查詢,並且同時需要考慮如何更好的滿足排序和分組的需要;

  • 在一個多列B-Tree索引中,索引列的順序意味着索引首先按照最左列進行排序,其次是第二列,以此類推,故多列索引的列順序至關重要;

  • 選擇索引列順序的經驗法則:將選擇性最高的列放在前面通常是很好的;

聚簇索引

  • 並非一種單獨的索引類型,而是一種數據存儲方式;

  • 因爲是存儲引擎負責實現索引,故並不是所有的存儲引擎都支持聚簇索引,但對InnoDB是適用的;

  • InnoDB的聚簇索引在同一個結構中保存了B-Tree索引和數據行;

  • 當表有聚簇索引時,它的數據行實際上存放在索引的葉子頁中,所謂“聚簇”,即表示數據行和相鄰的鍵值緊湊的存儲在一起;

  • 一個表只能有一個聚簇索引;

  • InnoDB通過主鍵聚集數據;

  • 如果沒有定義主鍵,InnoDB會選擇一個唯一的非空索引代替;如果沒有這樣的索引,則會隱式定義一個主鍵來作爲聚簇索引;

  • InnoDB只聚集在同一頁面中的記錄,包含相鄰鍵值的頁面可能會相距甚遠;

  • 聚簇索引的數據分佈如下:

    wKiom1NWcCCRcWpAAAS-P7wYtTU784.jpg

優點

  • 可以把相關數據保存在一起;

  • 數據訪問更快,因爲聚簇索引將索引和數據保存在同一個B-Tree中,因此從聚簇索引中獲取數據通常比在非聚簇索引中查找要快;

  • 使用覆蓋索引掃描的查詢可以直接使用頁節點中的主鍵值;

缺點

  • 聚簇索引最大限度的提高了I/O密集型應用的性能,但如果數據全部都放在內存中,則訪問速度就沒那麼重要了,聚簇索引也就沒什麼優勢了;

  • 插入速度嚴重依賴於插入順序,按照主鍵的順序插入是加載數據到InnoDB表中速度最快的方式;

  • 更新聚簇索引的代價很高,因爲會強制InnoDB將每個被更新的行移動到新的位置;

  • 基於聚簇索引的表在插入新行,或者主鍵被更新導致需要移動行的時候,可能面臨“也分裂”問題;

  • 聚簇索引可能導致全表掃描變慢,尤其是行比較疏鬆,或者由於頁分裂導致數據存儲不連續的時候;

  • 二級索引(非聚簇索引)可能比想象的要更大;且二級索引訪問需要兩次索引查找;

聚簇索引和非聚簇索引的區別

  • 聚簇索引的順序就是數據的物理存儲順序,葉節點就是數據節點;

  • 非聚簇索引的順序與數據物理排序順序無關,葉節點仍然是索引節點,只不過有一個指針指向對應的數據塊;

  • 聚簇索引和非聚簇索引的對比圖如下:

  • wKioL1NWcO2yFv5MAAWr3XmBZj0071.jpg

覆蓋索引

  • 如果一個索引包含所有需要查詢的字段的值,則稱之爲“覆蓋索引”

  • 覆蓋索引必須要存儲索引列的值,而哈希索引、空間索引和全文索引等都不存儲索引列的值,故MySQL只能使用B-Tree索引做覆蓋索引;

  • 當發起一個被索引覆蓋的查詢(也叫做索引覆蓋查詢)時,在explain的Extra列可以看到“Using index”的信息;

優點

  • 索引條目通常遠小於數據行大小,所以如果只需要讀取索引,那MySQL就會極大地減少數據訪問量;

  • 因爲索引是按照列值順序存儲的,所以對於I/O密集型的範圍查詢會比隨機從磁盤讀取每一行數據的I/O要少的多;

  • 一些存儲引擎如MyISAM在內存中只緩存索引,數據則依賴於操作系統來緩存,那麼覆蓋索引就可以避免訪問數據時的大量系統調用;

  • InnoDB的二級索引在葉子節點中保存了行的主鍵值,若二級主鍵能夠覆蓋查詢,則可以避免對主鍵索引的二次查詢;


評價一個索引是否適合某個查詢的“三星系統”

  • 索引將相關的記錄放在一起則獲得一星;

  • 如果索引中的數據順序和查找中的排列順序一致則獲得二星;

  • 如果索引中的列包含了查詢中需要的全部列則獲得三星;


MySQL中索引查看及添加

  • show indexes from students\G #顯示錶中索引

  • explain select查詢語句 #顯示查詢的執行過程

  • alter table students add index(Age); #添加索引


上一篇:MySQL深入05-用戶管理

下一篇:MySQL深入07-查詢緩存


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章