再一次學習 MySQL 索引

前言

提到數據庫索引,你們確定很熟悉,在平常工做中常常會接觸到。這幾天看了很多相關文章、書籍和課程。決定本身總結一篇文章,雖然我寫的這篇文章確定不如網上各路大神的好文,可是本身總結一遍總歸記得更牢固 🤓。這應該也是一種好的學習習慣,別人寫的字再漂亮都是別人的,本身寫的字就算再潦草起碼本身也能認識吧 😂。html

索引是一種提升咱們查詢效率的數據結構。就好像是字典的目錄,一本幾百頁的字典,若是想快速查詢到某個字,總不能靠硬翻吧 😫。mysql

索引結構

結論

MySQL 索引通常是哈希表或 B+ 樹,經常使用的 InnoDB 引擎默認使用的是 B+ 樹來做爲索引的數據結構。面試

爲何不用哈希表?

若是使用 B+ 樹做爲索引數據結構,那麼訪問或修改一條數據的時間複雜度是 O(log n),可是使用哈希表做爲索引結構幹這些活的時候,時間複雜度 O(1)。若是隻是查一條數據或者修改一條數據,用哈希表作索引確定給力呀!可是通常業務系統不會這麼簡單。sql

在業務開發中,常常會遇到範圍查詢、排序查詢等需求。這個時候哈希表索引就沒辦法高效的處理這些需求了。它只能經過掃表來實現這些功能,掃表應該是數據庫的噩夢吧 😩。數據庫

MySQL 使用 B+ 樹數據結構非葉子節點只儲存鍵值,葉子節點會儲存數據或者是主鍵。而且在葉子節點中鍵是按照順序存儲的,使得範圍查詢、排序查詢等變得異常簡單。編程

雖然哈希表索引在操做單列數據的時候十分高效,可是須要範圍查詢、排序查詢的時候,B+ 樹數據結構顯然更合適。在咱們業務開發中,不可能只操做一行數據。綜合考慮,仍是 B+ 樹更適合做爲索引的數據結構。數據結構

哈希表索引不支持範圍查詢,不能利用索引來排序,不支持聯合索引最左匹配原則,若是重複鍵值比較多,還容易形成哈希碰撞致使效率進一步下降 😂。學習

爲何不用 B 樹?

B+ 樹的非葉子節點上只儲存鍵值,而 B 樹的非葉子節點上不只儲存鍵值還儲存數據。在 MySQL 數據庫中數據頁的大小是固定的,Innodb 引擎數據頁默認大小爲 16 KB。B+ 樹這種作法是爲了讓樹的階數更大,讓樹更矮胖。進行查詢的時候,磁盤 IO 次數就會減小,查詢效率也會更快。優化

B+ 樹的全部數據均儲存在葉子節點中,而且是按鍵值有序排列。可是 B 樹的數據分散在各個節點。進行範圍查詢,排序查詢的時候,B 樹的效率確定不如 B+ 樹。阿里雲

B+ 樹查找過程

磁盤塊 1 中存儲 17 和 35 數據項,還有 P一、P二、P3 指針,P1 表示數據項小於 17 的磁盤塊,P2 表示數據項在 17 和 35 之間的數據項,P3 表示數據項大於 35 的數據項。非葉子節點不儲存數據,只儲存指引搜索方向的數據項。

咱們知道每次 IO 讀取一個數據頁的大小,也就是一個磁盤塊。假設咱們要查找 29 這個數據項,首先進行第一次 IO 將磁盤塊 1 讀進內存,發現 17 < 29 < 35,而後選用 P2 指針進行第二次 IO 將磁盤塊 3 讀進內存,發現 26 < 29 < 30,而後選用 P2 指針將磁盤塊 8 讀進內存,在內存中作二分查找,找到 29,結束查詢。

經過分析查詢過程,咱們能夠知道 IO 次數和 B+ 樹的高度成正比。H 爲樹的高度,M 爲每一個磁盤塊的數據項個數,N 爲數據項總數。從下面的公式能夠看出若是數據量 N 必定,M 越大相應的 H 就越小。

M 等於磁盤塊的大小除以數據項大小,因爲磁盤塊大小通常是固定的,因此減少數據項大小才能使得 M 更大從而讓樹更矮胖。這也是爲何 B+ 樹把真實數據放在葉子節點而不是非葉子節點的緣由,若是真實數據放在非葉子結點,磁盤塊存儲的數據項會大幅度減小,樹就會增高相應查詢數據時的 IO 次數就會變多。

B+ 樹通常能儲存多少數據?

這裏咱們先假設 B+ 樹高爲 2,即存在一個根節點和若干個葉子節點,假設一行記錄的數據大小爲 1 KB,那麼單個葉子節點(頁)中的記錄數等於 16 KB / 1 KB = 16 條數據。

而後要計算出非葉子節點能存放多少指針,咱們假設主鍵 ID 爲 bigint 類型,長度爲 8 字節,而指針大小在 InnoDB 源碼中設置爲 6 字節,這樣一共 14 字節,咱們一個頁中能存放多少這樣的單元,其實就表明有多少指針,即 16 KB / 14 B = 1170。那麼能夠算出一棵高度爲 2 的 B+ 樹,大概就能存放下 1170 * 16 = 18720 條數據。

根據一樣的原理咱們能夠算出一個高度爲 3 的 B+ 樹就能夠存放下 21902400 條數據。因此在 InnoDB 中 B+ 樹高度通常爲 1 - 3 層,它就能知足千萬級的數據存儲。在查找數據時一次頁的查找表明一次 IO,因此經過主鍵索引查詢一般只須要 1 - 3 次邏輯 IO 操做便可查找到數據。

總結

  1. 哈希表索引操做單數據行的時候很快,可是不支持範圍查詢,不能利用索引來排序,不支持聯合索引最左匹配原則。
  2. B 樹的數據能夠存儲在非葉子節點中,範圍查詢時可能會有額外的隨機磁盤 IO。並且因爲真實數據存放在非葉子節點中,B 樹的高度確定要高於一樣狀況下的 B+ 樹。這樣也不利於提高效率。
  3. B+ 樹把真實數據存儲在葉子節點中是爲了讓樹更矮胖,減小 IO 次數,提高效率。

最後

這是我學習 MySQL 索引結構記錄下的一些筆記 📝,以後也還會總結一篇索引使用的相關注意事項。我發現閱讀完各路大神的文章以後,再本身寫一遍印象會深入許多。雖然是炒舊飯,但也是炒給本身吃 😂。但願你們多多給我鼓勵,哈哈哈哈哈。

參考文章

我覺得我對 MySQL 索引很瞭解,直到我遇到了阿里的面試官。
爲何 MySQL 使用 B+ 樹 - 面向信仰編程
一篇文章講透MySQL爲何要用B+樹實現索引 - 騰訊雲
面試題:InnoDB中一棵B+樹能存多少行數據?- 騰訊雲
MySQL索引原理及慢查詢優化 - 美團技術團隊
搞懂Mysql InnoDB B+樹索引 - 阿里雲開發者社區

相關文章
相關標籤/搜索