MySQL - 剖析MySQL索引底层数据结构
文章目錄
- 更多干貨
- Pre
- 索引的數(shù)據(jù)結(jié)構(gòu)選型
- 二叉樹 ?
- 紅黑樹 ?
- B-Tree ?
- B+Tree
- Hash表
- 搞定MySQL
更多干貨
帶你搞定MySQL實戰(zhàn),輕松對應海量業(yè)務處理及高并發(fā)需求,從容應對大場面試
Pre
什么是索引?
通俗的說就是為了提高效率專門設計的一種 排好序的數(shù)據(jù)結(jié)構(gòu)。
怎么理解呢?
舉個例子哈
如上數(shù)據(jù) ,假設有個SQL
select * from t where col2 = 22 ;如果沒有索引的話,是不是得逐行進行全表掃描,走磁盤IO…
如果加上一個合適的索引呢?
比如用一個二叉樹
二叉樹我們知道,右邊的比左邊大
那執(zhí)行剛才的SQL的話,第一條記錄是34 ,那我們查找的是22, 是不是就只要到它的左邊查找即可,因為右邊的數(shù)據(jù)都比34大,肯定沒有22 ,找到22 以后, 搞定 ,I/O次數(shù)是不是比剛才的全表掃描的次數(shù)少很多,那效率自然就高了。
索引的數(shù)據(jù)結(jié)構(gòu)選型
二叉樹 ?
可以用二叉樹嗎? 我們知道MySQL一般都有自增主鍵 ,id之類的字段
我們來演示下使用二叉樹來存儲這種自增的數(shù)據(jù)的話,會怎樣?
https://www.cs.usfca.edu/~galles/visualization/BST.html
那查詢
select * from t where id = 7自增主鍵的時候 這個二叉樹已經(jīng)退化成鏈表了。。。。。
想想,一個幾百萬數(shù)據(jù)量的表 ,查找某個大一點的id , 逐個查找比對 (這些數(shù)據(jù)也是存儲在磁盤上的,還得從磁盤上撈啊) 這I/O 這效率可想而知吧…
二叉樹 pass ,不考慮了
既然退化成鏈表了,那試試帶有平衡功能的樹 二叉平衡樹 (紅黑樹)?
自增主鍵, 退化為為鏈表
紅黑樹 ?
二叉樹既然在某些情況下會退化成鏈表, 那如果這棵樹能自動平衡呢?
這樣子是不可能變成鏈表了,
同樣 查詢
select * from t where id = 7三次磁盤I/O即可找到, 比剛才二叉樹的七次是少了些哈 ,自然查找效率也比二叉樹高了
可如果數(shù)據(jù)量幾百萬 上千萬呢?
這棵樹 得多高哇。。。
數(shù)據(jù)量大, 樹高問題
那既然樹高不好, 是不是如果可以控制樹的高度(比如 3 到4層的高度,這樣查詢起來還能接受),讓每一層能存儲更多的數(shù)據(jù),然后再分裂,這樣的話數(shù)據(jù)量相乘起來,也是不少了對吧,這樣就能存儲更多的數(shù)據(jù),這樣會不會好一點? ----> B-Tree
B-Tree ?
- 葉節(jié)點具有相同的深度, 葉節(jié)點之間指針為空
- 所有索引元素不重復
- 節(jié)點中的數(shù)據(jù)索引從左到右遞增排列
葉子節(jié)點之間的沒有指針,區(qū)別于B+樹。
data存儲的是數(shù)據(jù)對應的磁盤地址, k-v結(jié)構(gòu)。
我們來看下B-Tree的插入 (Max.Degree 設置為3 即 元素到了3個就分裂 )
查找一下
3次
MySQL也沒有使用B-Tree , 因為
除了存儲索引以外,還存儲了data(數(shù)據(jù)對應的磁盤地址) , 為了更多的存儲數(shù)據(jù),MySQL對B-Tree進行了很多改造
由此演進出了 B+Tree ,將data部分僅保留在葉子節(jié)點上,這樣的話同等的頁可以存儲更多而索引數(shù)據(jù)。
B+Tree
- 非葉子節(jié)點不存儲data,只存儲索引(冗余),可以放更多的索引
- 葉子節(jié)點包含所有索引字段
- 葉子節(jié)點用指針連接,提高區(qū)間訪問的性能
數(shù)據(jù)僅存儲在葉子節(jié)點, data可能是磁盤地址也可能是其他的列數(shù)據(jù),這個和存儲引擎有關(guān)系。
葉子節(jié)點之間有指針相連。
我們來算下 3層高的B+Tree能存儲多少數(shù)據(jù)結(jié)構(gòu)
假設是BigInt類型的數(shù)據(jù)
BigInt 占 8個字節(jié) ,同時還是用6個字節(jié)存儲了它指向的數(shù)據(jù)的物理地址
MySQL在使用innodb引擎的時候頁大小默認是16K ,查詢?nèi)缦?/p> mysql> SHOW GLOBAL STATUS like 'Innodb_page_size'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | Innodb_page_size | 16384 | +------------------+-------+ 1 row in set (0.00 sec)mysql>
假設 樹高為3 , 這樣的話,第一層即可以存儲 16KB * 1024 / (8B + 6B) = 1170
同樣的第二層也是1170 (第二層不是葉子結(jié)點,不存儲數(shù)據(jù))
第三層,存儲數(shù)據(jù),一般情況下一行數(shù)據(jù)的大小肯定不會超過1KB,那我們就按照1KB算吧
3層高的B+Tree , 存儲BitInt可以存儲 1170 * 1170 * 16 = 2千1 百萬。。。。這效率還是可以的哈
想一想 如果是4層高的數(shù) 1170 * 1170 * 1170 * 16 = 250多億數(shù)據(jù)。.。。。
當然了 都是估算, 如果換成其他類型的數(shù)據(jù),每個表的行數(shù)據(jù)的大小都是相關(guān)的,這也就是我們通常說的 MySQL的表到千萬級別就要分庫分表的理論依據(jù)了。
我們看下B+Tree的插入和查找
Hash表
- 對索引的key進行一次hash計算就可以定位出數(shù)據(jù)存儲的位置
- 很多時候Hash索引要比B+ 樹索引更高效
- 僅能滿足 “=”,“IN”,不支持范圍查詢
- hash沖突問題
對索引字段進行hash以后, 還存儲了數(shù)據(jù)對引得磁盤地址。
一般請款下,hash 比 b+tree的效率要高 ,但工作中絕大部分還是使用的B+Tree , 因為hash對范圍查找不是很友好,還要全表掃描。
為啥B+Tree 支持范圍查找?
我們知道B+Tree的葉子節(jié)點 有指針相連,從根節(jié)點找到對應的葉子節(jié)點后, 加上節(jié)點本身就是排好序的,所以范圍查找就恨輕松了。
B-Tree 沒有指針相連,所以要想范圍查找,還得從根節(jié)點重新找,效率肯定比B+樹低 。
搞定MySQL
總結(jié)
以上是生活随笔為你收集整理的MySQL - 剖析MySQL索引底层数据结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: APM - Javassist 入门 生
- 下一篇: MySQL - MySQL不同存储引擎