索引以及索引的實現

索引介紹

**索引:**排序形式的數據結構。

在數據之外,數據庫系統還維護着滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。

索引的優點:

索引不僅可以加快查詢速度,還能避免全表掃描。

減少I/O次數,加快檢索速度;根據索引分組和排序,可以加快分組和排序;

索引的缺點:

索引本身是表,因此會佔用存儲空間,並且索引也會佔用磁盤空間。

創建索引時需要對錶加鎖。

一般來說,索引表佔用的空間的數據表的1.5倍;索引表的維護和創建需要時間成本,這個成本隨着數據量增大而增大;構建索引會降低數據表的修改操作(刪除,添加,修改)的效率,因爲在修改數據表的同時還需要修改索引表。

索引的分類

**主鍵索引:**即主索引,根據主鍵pk_clolum(length)建立索引,不允許重複,不允許空值

唯一索引:用來建立索引的列的值必須是唯一的,允許空值

**普通索引:**用表中的普通列構建的索引,沒有任何限制;

**全文索引:**用大文本對象的列構建的索引;

**組合索引:**用多個列組合構建的索引,這多個列中的值不允許有空值。

索引實現的原理

上面說了索引就是一種數據結構。

一、哈希索引:

只有memory(內存)存儲引擎支持哈希索引,哈希索引用索引列的值計算該值的hashCode,然後在hashCode相應的位置存執該值所在行數據的物理位置,因爲使用散列算法,因此訪問速度非常快,但是一個值只能對應一個hashCode,而且是散列的分佈方式,因此哈希索引不支持範圍查找和排序的功能。

二、全文索引:

FULLTEXT(全文)索引,僅可用於MyISAM和InnoDB,針對較大的數據,生成全文索引非常的消耗時間和空間。對於文本的大對象,或者較大的CHAR類型的數據,如果使用普通索引,那麼匹配文本前幾個字符還是可行的,但是想要匹配文本中間的幾個單詞,那麼就要使用LIKE %word%來匹配,這樣需要很長的時間來處理,響應時間會大大增加,這種情況,就可使用時FULLTEXT索引了,在生成FULLTEXT索引時,會爲文本生成一份單詞的清單,在索引時及根據這個單詞的清單來索引。FULLTEXT可以在創建表的時候創建,也可以在需要的時候用ALTER或者CREATE INDEX來添加。全文索引的查詢也有自己特殊的語法,而不能使用LIKE %查詢字符串%的模糊查詢語法。

**三、BTree索引:**平衡的多叉查找樹/查找複雜度爲h*log(n)

設樹的度爲2d(d>1),高度爲h,那麼BTree要滿足以一下條件:

1.每個葉子結點的高度一樣,等於h;
2.每個非葉子結點由n-1個key和n個指針point組成,其中d<=n<=2d,key和point相互間隔,結點兩端一定是key;
3.葉子結點指針都爲null;
4.非葉子結點的key都是[key,data]二元組,其中key表示作爲索引的鍵,data爲鍵值所在行的數據;

**四、B+Tree索引:**BTree的一個變種

設d爲樹的度數,h爲樹的高度,B+Tree和BTree的不同主要在於:

1.B+Tree中的非葉子結點不存儲數據,只存儲鍵值;

2.B+Tree的葉子結點沒有指針,所有鍵值都會出現在葉子結點上,且key存儲的鍵值對應data數據的物理地址;

3.B+Tree的每個非葉子節點由n個鍵值keyn個指針point組成;

MySQL爲什麼使用B樹(B+樹)

根據B-Tree的定義,可知檢索一次最多需要訪問h個節點。數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每個節點只需要一次I/O就可以完全載入。爲了達到這個目的,在實際實現B-Tree還需要使用如下技巧:

每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裏,加之計算機存儲分配都是按頁對齊的,就實現了一個node只需一次I/O。

B-Tree中一次檢索最多需要h-1次I/O(根節點常駐內存),漸進複雜度爲
O(h)=O(logdN) O(h)=O(logdN)
一般實際應用中,出度d是非常大的數字,通常超過100,因此h非常小(通常不超過3)。

(h表示樹的高度 & 出度d表示的是樹的度,即樹中各個節點的度的最大值)

綜上所述,用B-Tree作爲索引結構效率是非常高的。

而紅黑樹這種結構,h明顯要深的多。由於邏輯上很近的節點(父子)物理上可能很遠,無法利用局部性,所以紅黑樹的I/O漸進複雜度也爲O(h),效率明顯比B-Tree差很多。

上文還說過,B+Tree更適合外存索引,原因和內節點出度d有關。從上面分析可以看到,d越大索引的性能越好,而出度的上限取決於節點內key和data的大小:
dmax=floor(pagesize/(keysize+datasize+pointsize)) dmax=floor(pagesize/(keysize+datasize+pointsize))
floor表示向下取整。由於B+Tree內節點去掉了data域,因此可以擁有更大的出度,擁有更好的性能。

Mysql索引的實現

在MySQL中,索引屬於存儲引擎級別的概念,不同存儲引擎對索引的實現方式是不同的。

MyISAM索引實現/B+Tree作爲索引結構:

MyISAM引擎使用B+Tree作爲索引結構,葉節點的data域存放的是數據記錄的地址。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iShbzZGh-1571272349797)(https://NolanJcn.github.io/pic_lalala/Primarykey_meitu_1.jpg)]

這裏設表一共有三列,假設我們以Col1爲主鍵,則上圖是一個MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件僅僅保存數據記錄的地址。在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重複。如果我們在Col2上建立一個輔助索引,則此索引的結構如下圖所示:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-55Og84uY-1571272349800)(https://NolanJcn.github.io/pic_lalala/Secondarykey_meitu_2.jpg)]

同樣也是一棵B+樹,data域保存數據記錄的地址。因此,MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然後以data域的值爲地址,讀取相應數據記錄。

MyISAM的索引方式也叫做“非聚集”的,之所以這麼稱呼是爲了與InnoDB的聚集索引區分。

InnoDB索引實現/B+Tree作爲索引結構:

第一個重大區別是InnoDB的數據文件本身就是索引文件。從上文知道,MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件本身就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,因此InnoDB表數據文件本身就是主索引。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Etr0jkDm-1571272349802)(https://NolanJcn.github.io/pic_lalala/Primarykey1_meitu_3.jpg)]

上圖是InnoDB主索引(同時也是數據文件)的示意圖,可以看到葉節點包含了完整的數據記錄。這種索引叫做聚集索引。因爲InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作爲主鍵,如果不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段作爲主鍵,這個字段長度爲6個字節,類型爲長整型。

第二個與MyISAM索引的不同是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作爲data域。例如,上圖爲定義在Col3上的一個輔助索引:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TfQS36a4-1571272349802)(https://NolanJcn.github.io/pic_lalala/Secondarykey1_meitu_5.jpg)]

這裏以英文字符的ASCII碼作爲比較準則。聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然後用主鍵到主索引中檢索獲得記錄。

瞭解不同存儲引擎的索引實現方式對於正確使用和優化索引都非常有幫助,例如知道了InnoDB的索引實現後,就很容易明白爲什麼不建議使用過長的字段作爲主鍵,因爲所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。再例如,用非單調的字段作爲主鍵在InnoDB中不是個好主意,因爲InnoDB數據文件本身是一棵B+Tree,非單調的主鍵會造成在插入新記錄時數據文件爲了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用自增字段作爲主鍵則是一個很好的選擇。

參考文章:

https://blog.csdn.net/tongdanping/article/details/79878302#commentBox

https://www.cnblogs.com/boothsun/p/8970952.html#autoid-0-0-0

https://www.cnblogs.com/bnuvincent/p/9011324.html

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