日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

在我們的印象中,MySQL數(shù)據(jù)表里無非就是存儲一行行的數(shù)據(jù)。跟個Excel似的。

直接遍歷這一行行數(shù)據(jù),性能就是O(n),比較慢。為了加速查詢,使用了B+樹來做索引,將查詢性能優(yōu)化到了O(lg(n))

但問題就來了,查詢數(shù)據(jù)性能在 lg(n) 級別的數(shù)據(jù)結(jié)構(gòu)有很多,比如redis的zset里用到的跳表,也是lg(n),并且實現(xiàn)還賊簡單。

那為什么mysql的索引,不使用跳表呢?

我們今天就來聊聊這個話題。

 

B+樹的結(jié)構(gòu)

之前的一篇文章里,已經(jīng)提到過B+樹的結(jié)構(gòu)了。文章不長,如果沒看過,建議先看下。

當然,不看也行。

在這里,為了混點字數(shù),我簡單總結(jié)下B+樹的結(jié)構(gòu)。

Mysql的索引為什么使用B+樹而不使用跳表?

 

B+樹查詢過程

如上圖,一般B+樹是由多個頁組成的多層級結(jié)構(gòu),每個頁16Kb,對于主鍵索引來說,最末級的葉子結(jié)點放行數(shù)據(jù),非葉子結(jié)點放的則是索引信息(主鍵id和頁號),用于加速查詢。

比方說我們想要查找行數(shù)據(jù)5。會先從頂層頁的record們?nèi)胧帧?strong>record里包含了主鍵id和頁號(頁地址)。關(guān)注黃色的箭頭,向左最小id是1,向右最小id是7。那id=5的數(shù)據(jù)如果存在,那必定在左邊箭頭。于是順著的record的頁地址就到了6號數(shù)據(jù)頁里,再判斷id=5>4,所以肯定在右邊的數(shù)據(jù)頁里,于是加載105號數(shù)據(jù)頁。

在105號數(shù)據(jù)頁里,雖然有多行數(shù)據(jù),但也不是挨個遍歷的,數(shù)據(jù)頁內(nèi)還有個頁目錄的信息,它可以通過二分查找的方式加速查詢行數(shù)據(jù),于是找到id=5的數(shù)據(jù)行,完成查詢。

從上面可以看出,B+樹利用了空間換時間的方式(構(gòu)造了一批非葉子結(jié)點用于存放索引信息),將查詢時間復(fù)雜度從O(n)優(yōu)化為O(lg(n))

 

跳表的結(jié)構(gòu)

看完B+樹,我們再來看下跳表是怎么來的。

同樣的,還是為了存儲一行行的數(shù)據(jù)。

我們可以將它們用鏈表串起來。

Mysql的索引為什么使用B+樹而不使用跳表?

 

單鏈表

想要查詢鏈表中的其中一個結(jié)點,時間復(fù)雜度是O(n),這誰頂?shù)米。谑菍?strong>部分鏈表結(jié)點提出來,再構(gòu)建出一個新的鏈表。

Mysql的索引為什么使用B+樹而不使用跳表?

 

兩層跳表

這樣當我想要查詢一個數(shù)據(jù)的時候,我先查上層的鏈表,就很容易知道數(shù)據(jù)落在哪個范圍,然后跳到下一個層級里進行查詢。這樣就把搜索范圍一下子縮小了一大半。

比如查詢id=10的數(shù)據(jù),我們先在上層遍歷,依次判斷1,6,12,很快就可以判斷出10在6到12之間,然后往下一跳,就可以在遍歷6,7,8,9,10之后,確定id=10的位置。直接將查詢范圍從原來的1到10,變成現(xiàn)在的1,6,7,8,9,10,算是砍半了。

Mysql的索引為什么使用B+樹而不使用跳表?

 

兩層跳表查找id為10的數(shù)據(jù)

既然兩層鏈表就直接將查詢范圍砍半了,那我多加幾層,豈不妙哉?

于是跳表就這樣變成了多層。

Mysql的索引為什么使用B+樹而不使用跳表?

 

三層跳表

如果還是查詢id=10的數(shù)據(jù),就只需要查詢1,6,9,10就能找到,比兩層的時候更快一些。

Mysql的索引為什么使用B+樹而不使用跳表?

 

三層跳表查詢id為10的數(shù)據(jù)

可以看出,跳表也是通過犧牲空間換取時間的方式提升查詢性能。時間復(fù)雜度都是lg(n)

 

B+樹和跳表的區(qū)別

從上面可以看到,B+樹和跳表的最下面一層,都包含了所有的數(shù)據(jù),且都是順序的,適合用于范圍查詢。往上的層級都是構(gòu)建出來用于提升搜索性能的。這兩者實在是太像了。但他們兩者在新增和刪除數(shù)據(jù)時,還是有些區(qū)別的。下面我們以新增數(shù)據(jù)為例聊一下。

 

B+樹新增數(shù)據(jù)會怎么樣

B+樹本質(zhì)上是一種多叉平衡二叉樹。關(guān)鍵在于"平衡"這兩個字,對于多叉樹結(jié)構(gòu)來說,它的含義是子樹們的高度層級盡量一致(一般最多差一個層級),這樣在搜索的時候,不管是到哪個子樹分支,搜索次數(shù)都差不了太多。

當數(shù)據(jù)庫表不斷插入新的數(shù)據(jù)時,為了維持B+樹的平衡,B+樹會不斷分裂調(diào)整數(shù)據(jù)頁。

我們知道B+樹分為葉子結(jié)點和非葉子結(jié)點

當插入一條數(shù)據(jù)時,葉子結(jié)點和它上層的索引結(jié)點(非葉子結(jié)點)最大容量都是16k,它們都有可能會滿。

為了簡化問題,我們假設(shè)一個數(shù)據(jù)頁只能放三條行數(shù)據(jù)或索引。

加入一條數(shù)據(jù),根據(jù)數(shù)據(jù)頁會不會滿,分為三種情況。

  • 葉子結(jié)點和索引結(jié)點都沒滿。這種情況最簡單,直接插入到葉子結(jié)點中就好了。
Mysql的索引為什么使用B+樹而不使用跳表?

 

葉子和非葉子都未滿

  • 葉子結(jié)點滿了,但索引結(jié)點沒滿。此時需要拆分葉子結(jié)點,同時索引結(jié)點要增加新的索引信息。
Mysql的索引為什么使用B+樹而不使用跳表?

 

葉子滿了但非葉子未滿.drawio

  • 葉子結(jié)點滿了,且索引結(jié)點也滿了。葉子和索引結(jié)點都要拆分,同時往上還要再加一層索引。
Mysql的索引為什么使用B+樹而不使用跳表?

 

葉子和非葉子都滿了

從上面可以看到,只有在葉子和索引結(jié)點都滿了的情況下,B+樹才會考慮加入一層新的結(jié)點。

而從之前的文章知道,要把三層B+樹塞滿,那大概需要2kw左右的數(shù)據(jù)。

 

跳表新增數(shù)據(jù)

跳表同樣也是很多層,新增一個數(shù)據(jù)時,最底層的鏈表需要插入數(shù)據(jù)。

此時,是否需要在上面的幾層中加入數(shù)據(jù)做索引呢?

這個就純靠隨機函數(shù)了。

理論上為了達到二分的效果,每一層的結(jié)點數(shù)需要是下一層結(jié)點數(shù)的二分之一。

也就是說現(xiàn)在有一個新的數(shù)據(jù)插入了,它有50%的概率需要在第二層加入索引,有25%的概率需要在第三層加個索引,以此類推,直到最頂層。

舉個例子,如果跳表中插入數(shù)據(jù)id=6,且隨機函數(shù)返回第三層(有25%的概率),那就需要在跳表的最底層到第三層都插入數(shù)據(jù)。

Mysql的索引為什么使用B+樹而不使用跳表?

 

跳表插入數(shù)據(jù)

如果這個隨機函數(shù)設(shè)計成上面這樣,當數(shù)據(jù)量樣本足夠大的時候,數(shù)據(jù)的分布就符合我們理想中的"二分"。

跟上面B+樹不一樣,跳表是否新增層數(shù),純粹靠隨機函數(shù),根本不關(guān)心前后上下結(jié)點。

 

好了,基礎(chǔ)科普也結(jié)束了,我們可以進入正題了。

 

Mysql的索引為什么使用B+樹而不使用跳表?

B+樹是多叉樹結(jié)構(gòu),每個結(jié)點都是一個16k的數(shù)據(jù)頁,能存放較多索引信息,所以扇出很高三層左右就可以存儲2kw左右的數(shù)據(jù)(知道結(jié)論就行,想知道原因可以看之前的文章)。也就是說查詢一次數(shù)據(jù),如果這些數(shù)據(jù)頁都在磁盤里,那么最多需要查詢三次磁盤IO

 

跳表是鏈表結(jié)構(gòu),一條數(shù)據(jù)一個結(jié)點,如果最底層要存放2kw數(shù)據(jù),且每次查詢都要能達到二分查找的效果,2kw大概在2的24次方左右,所以,跳表大概高度在24層左右。最壞情況下,這24層數(shù)據(jù)會分散在不同的數(shù)據(jù)頁里,也即是查一次數(shù)據(jù)會經(jīng)歷24次磁盤IO

因此存放同樣量級的數(shù)據(jù),B+樹的高度比跳表的要少,如果放在mysql數(shù)據(jù)庫上來說,就是磁盤IO次數(shù)更少,因此B+樹查詢更快

而針對寫操作,B+樹需要拆分合并索引數(shù)據(jù)頁,跳表則獨立插入,并根據(jù)隨機函數(shù)確定層數(shù),沒有旋轉(zhuǎn)和維持平衡的開銷,因此跳表的寫入性能會比B+樹要好。

其實,mysql的存儲引擎是可以換的,以前是myisam,后來才有的innodb,它們底層索引用的都是B+樹。也就是說,你完全可以造一個索引為跳表的存儲引擎裝到mysql里。事實上,facebook造了個rocksDB的存儲引擎,里面就用了跳表。直接說結(jié)論,它的寫入性能確實是比innodb要好,但讀性能確實比innodb要差不少。感興趣的話,可以在文章最后面的參考資料里看到他們的性能對比數(shù)據(jù)。

 

redis為什么使用跳表而不使用B+樹或二叉樹呢?

redis支持多種數(shù)據(jù)結(jié)構(gòu),里面有個有序集合,也叫ZSET。內(nèi)部實現(xiàn)就是跳表。那為什么要用跳表而不用B+樹等結(jié)構(gòu)呢?

這個幾乎每次面試都要被問一下。

雖然已經(jīng)很熟了,但每次都要裝作之前沒想過,現(xiàn)場思考一下才知道答案。

真的,很考驗演技。

大家知道,redis 是純純的內(nèi)存數(shù)據(jù)庫。

進行讀寫數(shù)據(jù)都是操作內(nèi)存,跟磁盤沒啥關(guān)系,因此也不存在磁盤IO了,所以層高就不再是跳表的劣勢了。

并且前面也提到B+樹是有一系列合并拆分操作的,換成紅黑樹或者其他AVL樹的話也是各種旋轉(zhuǎn),目的也是為了保持樹的平衡

而跳表插入數(shù)據(jù)時,只需要隨機一下,就知道自己要不要往上加索引,根本不用考慮前后結(jié)點的感受,也就少了旋轉(zhuǎn)平衡的開銷

因此,redis選了跳表,而不是B+樹。

 

總結(jié)

  • B+樹是多叉平衡搜索樹,扇出高,只需要3層左右就能存放2kw左右的數(shù)據(jù),同樣情況下跳表則需要24層左右,假設(shè)層高對應(yīng)磁盤IO,那么B+樹的讀性能會比跳表要好,因此mysql選了B+樹做索引。
  • redis的讀寫全在內(nèi)存里進行操作,不涉及磁盤IO,同時跳表實現(xiàn)簡單,相比B+樹、AVL樹、少了旋轉(zhuǎn)樹結(jié)構(gòu)的開銷,因此redis使用跳表來實現(xiàn)ZSET,而不是樹結(jié)構(gòu)。
  • 存儲引擎RocksDB內(nèi)部使用了跳表,對比使用B+樹的innodb,雖然寫性能更好,但讀性能屬實差了些。在讀多寫少的場景下,B+樹依舊YYDS。

參考資料

《MYSQL內(nèi)核:INNODB存儲引擎 卷1》

《RocksDB和Innodb引擎性能PK勝負難料?》

https://cloud.tencent.com/developer/article/1813695

 

最后

最近在看《龍蛇演義》,劇情很一般,但我硬是一口氣看到了最新一集,還很上頭。

為啥?

點開它,看到女主角的時候你就理解我了。

Mysql的索引為什么使用B+樹而不使用跳表?

 

這么說吧,一個顏值出眾,身材火辣的姐姐,還是個世界頂級的武術(shù)高手,穿著旗袍,踩著高跟,做著各種讓牛頓棺材板都快要按不住的動作,只為手把手教會你武術(shù)基本功。

這時候,劇情還重要嗎?

不得不說,當我看到姐姐穿成這樣用木棍頂起400斤的汞球時。

Mysql的索引為什么使用B+樹而不使用跳表?

 

我可以肯定,導(dǎo)演根本不懂物理。

 

但是!

 

導(dǎo)演很懂男人!

 

這不得不讓我陷入沉思,到底什么才是好的內(nèi)容?

難道現(xiàn)在有個大姐姐穿個黑絲高跟超短裙,教你變量的聲明和定義這么基礎(chǔ)的東西,你也會去看嗎?

我不知道你們會不會。

 

反正我會。

分享到:
標簽:索引 Mysql
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定