innodb索引實現原理

  對於innodb索引,採用是的B+tree的數據結構,及索引和數據都存儲在一個文件中*.db;而不像MYISAM索引和數據是分開存儲的.

舉例說明,下面是students表,id是主鍵,name上有輔助索引,有6行數據記錄。

  • 一級索引(聚簇索引)

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

  • 二級索引(非聚簇索引)

對於secondary index,非葉子結點保存的是索引值,比如上面的name字段。葉子結點保存的不再是數據記錄了,而是主鍵值。

  • innodb索引總結

MySQL聚集索引使得按主鍵的搜索非常高效的。
輔助索引需要搜索兩遍索引:
         第一:檢索輔助索引獲得主鍵值

         第二:用主鍵值到主鍵索引中檢索獲得記錄

爲什麼Innodb表需要主鍵?

     1)innodb表數據文件都是基於主鍵索引組織的,沒有主鍵,mysql會想辦法給我搞定,所以主鍵必須要有;
     2)基於主鍵查詢效率高;
     3)其他類型索引都要引用主鍵索引;

爲什麼不建議Innodb表主鍵設置過長?

  因爲輔助索引都保存引用主鍵索引,過長的主鍵索引使輔助索引變得過大;
  • innodb對B-TREE的改進

在上面的例子中:將下面數字插入到一棵5階B-Tree中:[3,14,7,1,8,5,11,17,13,6,23,12,20,26,4,16,18,24,25,19]

插入這些無序數據一共經歷了6次分裂,對於磁盤索引文件而言,每次分裂都是很昂貴的操作;

如果將以上數據排好序,再次插入是不是效果會好,我試驗了下,雖然每次都是插入到最右結點,涉及遷移數據量會少,但是分裂的次數依然挺多,需要7次分裂。

每次分裂都是按照50%進行,這樣存在明顯的缺點就是導致索引頁面的空間利用率在50%左右;而且對於遞增插入效率也不好,平均每兩次插入,最右結點就得進行一次分裂。那Innodb是如何進行改進的呢?

Innodb其實只是針對遞增/遞減情況進行了改進優化,不再採用50%的分裂策略,而是使用下面的分裂策略:

對於遞增/遞減索引插入操作:
1、插入新元素,判斷葉子結點空間是否足夠,如果足夠,直接插入
2、如果葉子結點空間滿了,判斷父結點空間是否足夠,如果足夠,將該新元素插入到父結點中;如果父結點空間滿了,則進行分裂。

比如下面一棵5階B+Tree:

現在連續插入10,11,14,15,17,採用優化後分裂策略的分步圖例如下:

【第一步】:插入10

 

由於最右結點還有空間,直接插入即可。

【第二步】:插入11

 

 

插入11時,由於最右結點空間已滿,如果使用50%分裂策略,則需要分裂操作了,但是使用優化後的分裂策略,當該結點空間已滿,還要判斷該結點的父結點是否滿了,如果父結點還有空間,那麼插入到父結點中,所以11插入到父結點中了,同時形成一個子結點。

 【第二步】:插入14,15,17

 

優化後的分裂策略僅僅針對遞增/遞減情況,顯著的減少了分裂次數並且大大提高了索引頁面空間的利用率。

如果是隨機插入,可能會引起更高代價的分裂概率。所以InnoDB存儲引擎會爲每個索引頁維護一個上次插入的位置變量,以及上次插入是遞增/遞減的標識。InnoDB能夠根據這些信息判斷新插入數據是否滿足遞增/遞減條件,若滿足,則採用改進後的分裂策略;若不滿足,則進行50%的分裂策略。

爲什麼建議InnoDB表主鍵是單調遞增?

如果InnoDB表主鍵是單調遞增的,可以使用改進後的B+tree分裂策略,顯著減少B-Tree分裂次數和數據遷移,從而提高數據插入效率。不僅如此,它還大大提高索引頁空間利用率。


 參考文章:

     http://database.51cto.com/art/201107/275030_1.html

     http://www.2cto.com/database/201411/351106.html

     http://hedengcheng.com/?p=525

     https://www.cnblogs.com/mysql-dba/p/6689597.html





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