MySql数据库索引底层数据结构
索引是幫助數據庫高效獲取數據的排好序的數據結構。
數據是如何存儲與讀取的?
1. 索引采用了什么數據結構呢?
? ? ? ?常見的數據結構有:hash、二叉樹、紅黑樹、B樹、B+樹。
? ? ? ?首先來看如果采用Hash,它是把數據進行Hash直接對應磁盤存儲引用地址,這樣查找數據直接告訴磁盤數據在哪,查詢很快。但是 hash 還是有些不足:那就是不能范圍查找,如果通過大于或者小于去篩選數據,就需要掃描整個hash表,效率大大降低了。當然mysql還是提供了Hash索引,畢竟有些場合還是用起來也不錯。
? ? ? ?采用二叉樹,每個節點存儲了索引對應字段的值,這樣我們根據索引去查詢時就可以避免全表掃描,時間復雜度降為O(log n)。看起來很美好,但是二叉樹在值單邊遞增的情況下回退化到鏈表。
采用紅黑樹,又叫自平衡二叉樹,會通過特定操作保持二叉查找樹的平衡,避免了單邊增長的問題,從而獲得較高的查找性能。
? ? ? ?從上面我們發現,紅黑樹相比較于二叉樹又進步了一些,但紅黑樹還是有些問題:那就是數據量大的話,紅黑樹的深度會很深,也就是說深度不可控,這樣一來查找數據還是會很耗時。100w數據時樹的高度大概在20左右,那也就是說從有著100w條數據的平衡二叉樹中找一個數據,最壞的情況下需要20次磁盤的IO查找。是不是可以每個節點多增加一些數據呢?
B樹的結構為:
動態演示數據結構的網站
B樹的特點:
1.葉子節點具有相同的深度,葉子節點的指針為空
2.所有索引元素不可重復
3.節點中數據索引是有序的,即從左到右遞增
實際上mysql使用的是B+樹
B+樹是在B樹基礎上的一種優化,使其更適合實現存儲索引結構。B+樹與B樹的結構很像,但是也有幾個自己的特性:
1、所有的非葉子節點只存儲索引信息,因此可以放更多的索引
2、葉子結點中包含了全部索引信息。
3、所有葉子節點之間都有一個鏈指針,來提高區間訪問的性能
? ? ? ?為什么要做這樣的改進呢?我們還需要了解的一個知識點是操作系統從磁盤讀取數據到內存是以磁盤塊(block)為基本單位的,位于同一個磁盤塊中的數據會被一次性讀取出來。即使只需要一個字節,磁盤也會從這個位置開始,順序向后讀取一定長度的數據放入內存。這樣做的理論依據是計算機科學中著名的局部性原理:當一個數據被用到時,其附近的數據也通常會馬上被使用。
? ? ? ?預讀的長度一般為頁(page)的整數倍,InnoDB預讀大小默認為16K。頁是計算機管理存儲器的邏輯塊,操作系統往往將磁盤存儲區分割為連續的大小相等的塊,每個存儲塊稱為一頁,在許多操作系統中頁的大小通常為4k。
B+樹相比B樹有哪些優勢呢?
1.由于B+樹所有的索引都在葉子結點,并且結點之間有指針連接,在找大于某個關鍵字或者小于某個關鍵字的數據的時候,B+樹只需要找到該關鍵字然后沿著鏈表遍歷就可以了,而B樹還需要遍歷該關鍵字結點的根結點去搜索。
2.由于B樹的每個結點(這里的結點可以理解為一個數據頁)都存儲索引+實際數據,而B+樹非葉子結點只存儲索引信息。而每個節點也就是每個頁的大小是有限的,所以B樹同一頁能存儲的數據會比B+樹存儲的更少。這樣同樣總量的數據,B樹的深度會更大,增大查詢時的磁盤I/O次數,進而影響查詢效率。
總的來說B+樹即減少了查詢次數也提高了很好的范圍查詢性能。
2. MyISAM和InnoDB
每個表可以使用不同的存儲引擎。開發中使用最多的是InnoDB存儲引擎。
索引屬于存儲引擎級別的概念,不同存儲引擎對索引的實現方式是不同的。下面主要討論MyISAM和InnoDB兩個存儲引擎的索引實現方式。
2.1 MyISAM的索引實現(非聚集)
MyISAM引擎使用B+Tree作為索引結構,葉節點的data域存放的是數據記錄的存儲地址。對應硬盤文件里每個表都有(.MYD data)數據 + (.MYI index)索引 + (.frm frame)結構三個文件。
下圖是MyISAM索引的原理圖:
? ? ? ?這里設表一共有三列,假設我們以Col1為主鍵,則下圖是一個MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件僅僅保存數據記錄的地址。
? ? ? ?在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重復。如果我們在Col2上建立一個輔助索引,則此索引的結構如下圖所示:
? ? ? ?同樣也是一棵B+樹,data域保存數據記錄的地址。因此MyISAM中索引檢索的算法為首先按照B+樹搜索算法搜索索引(索引還會緩存進內存),如果指定的Key存在,則取出其data域中保存的存儲地址,去磁盤讀取相應的數據記錄(稱為回表)。
2.2 InnoDB的索引實現(聚集索引)
? ? ? ?InnoDB的數據文件本身就是按B+樹組織的一個索引結構文件。MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件本身就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄,這個索引的key是數據表的主鍵。
? ? ? ?上圖是InnoDB主索引(同時也是表數據文件)的示意圖,可以看到葉子節點包含了完整的數據記錄。這種索引叫做聚集索引。
? ? ? ?第二個與MyISAM索引的不同是InnoDB的輔助索引data域存儲相應記錄主鍵的值。下圖為定義在Col3上的一個輔助索引:
? ? ? ?輔助索引的data存儲主鍵的節點不僅可以節省內存空間,而且利于保證數據的一致性,修改值只要修改主索引文件就行了。
? ? ? ?聚集索引這種實現方式使得如果按主鍵的搜索不需要回表操作比MyISAM高效很多,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄。
? ? ? ?了解不同存儲引擎的索引實現方式對于正確使用和優化索引都非常有幫助,例如知道了InnoDB的索引實現后,就很容易明白:
- 為什么不建議使用過長的字段作為主鍵?
因為所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。 - 為什么InnoDB必須要求有主鍵?
? ? ? ?InnoDB的數據文件本身按B+樹聚集,所以表必須有主鍵來作為唯一標識。如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作為主鍵,如果不存在這種列,則MySQL自動為InnoDB表生成一個隱含字段作為主鍵。 - 為什么InnoDB推薦使用整型的自增主鍵?
? ? ? ?首先選擇整型因為比較節省存儲空間。
? ? ? ?如果表使用自增主鍵,那么每次插入新的記錄,記錄就會順序添加到當前索引節點的后續位置,當一頁寫滿,就會自動開辟一個新的頁,不用重新排位。如果不是自增的主鍵,非有序增長的主鍵會造成在插入新記錄時數據文件為了維持B+Tree的特性而頻繁的分裂調整,頻繁的插入和刪除那會導致數據頁產生碎片,頁的空間利用率低,還會導致樹變的“虛高”,降低查詢效率!
聯合索引
開發中一般推薦使用聯合索引,因此很多索引的建立原則都和聯合索引有著重要關系
下面是聯合索引的底層存儲結構
總結
以上是生活随笔為你收集整理的MySql数据库索引底层数据结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (二)链表
- 下一篇: synchronized的底层原理