日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL - 剖析MySQL索引底层数据结构

發(fā)布時間:2025/3/21 数据库 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL - 剖析MySQL索引底层数据结构 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 更多干貨
  • 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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。