久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

一步步分析為什么B+樹適合作為索引的結(jié)構(gòu) 以及索引原理

 悅光陰 2022-03-25

 

https://www.cnblogs.com/aspirant/p/9214485.html

一步步分析為什么B+樹適合作為索引的結(jié)構(gòu) 以及索引原理 

 

mysql的B+樹索引 查找使用了二分查找,,redis 跳表也使用了二分查找法,kafka查詢消息日志也使用了二分查找法,,二分查找法時(shí)間復(fù)雜度O(logn);

參考:redis的索引底層的 跳表原理 實(shí)現(xiàn) 聊聊Mysql索引和redis跳表 ---redis的跳表原理 時(shí)間復(fù)雜度O(logn)(阿里)

參考:kafka如何實(shí)現(xiàn)高并發(fā)存儲-如何找到一條需要消費(fèi)的數(shù)據(jù)(阿里)

參考:二分查找法:各種排序算法的時(shí)間復(fù)雜度和空間復(fù)雜度(阿里)

在MySQL中,,主要有四種類型的索引,分別為:B-Tree索引,,Hash索引,,F(xiàn)ulltext索引(MyISAM 表)和R-Tree索引,本文講的是B-Tree索引,。

后面的索引原理一定要看,,太重要了,阿里兩個(gè)人都問這個(gè)mysql的索引原理

mysql使用了 B+索引:

B樹:有序數(shù)組+平衡多叉樹,; 
B+樹:有序數(shù)組鏈表+平衡多叉樹,;

一、Mysql索引主要有兩種結(jié)構(gòu):B+Tree索引和Hash索引 

(a) Inodb存儲引擎 默認(rèn)是 B+Tree索引

(b) MyISAM 存儲引擎 默認(rèn)是Fulltext索引,;

(c)Memory 存儲引擎 默認(rèn) Hash索引,;

Hash索引

mysql中,只有Memory(Memory表只存在內(nèi)存中,,斷電會消失,,適用于臨時(shí)表)存儲引擎顯示支持Hash索引,是Memory表的默認(rèn)索引類型,,盡管Memory表也可以使用B+Tree索引,。Hash索引把數(shù)據(jù)以hash形式組織起來,因此當(dāng)查找某一條記錄的時(shí)候,,速度非??臁5且?yàn)閔ash結(jié)構(gòu),,每個(gè)鍵只對應(yīng)一個(gè)值,,而且是散列的方式分布。所以它并不支持范圍查找和排序等功能,。

 

B+Tree索引

B+Tree是mysql使用最頻繁的一個(gè)索引數(shù)據(jù)結(jié)構(gòu),,是Inodb和Myisam存儲引擎模式的索引類型。相對Hash索引,,B+Tree在查找單條記錄的速度比不上Hash索引,,但是因?yàn)楦m合排序等操作,所以它更受歡迎。畢竟不可能只對數(shù)據(jù)庫進(jìn)行單條記錄的操作,。

帶順序訪問指針的B+Tree

B+Tree所有索引數(shù)據(jù)都在葉子節(jié)點(diǎn)上,,并且增加了順序訪問指針,每個(gè)葉子節(jié)點(diǎn)都有指向相鄰葉子節(jié)點(diǎn)的指針,。

這樣做是為了提高區(qū)間效率,,例如查詢key為從18到49的所有數(shù)據(jù)記錄,當(dāng)找到18后,,只要順著節(jié)點(diǎn)和指針順序遍歷就可以以此向訪問到所有數(shù)據(jù)節(jié)點(diǎn),,極大提高了區(qū)間查詢效率。

大大減少磁盤I/O讀取

數(shù)據(jù)庫系統(tǒng)的設(shè)計(jì)者巧妙利用了磁盤預(yù)讀原理,,將一個(gè)節(jié)點(diǎn)的大小設(shè)為等于一個(gè)頁,,這樣每個(gè)節(jié)點(diǎn)需要一次I/O就可以完全載入。 

 

什么是索引

索引(Index)是幫助數(shù)據(jù)庫高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),。索引是在基于數(shù)據(jù)庫表創(chuàng)建的,,它包含一個(gè)表中某些列的值以及記錄對應(yīng)的地址,并且把這些值存儲在一個(gè)數(shù)據(jù)結(jié)構(gòu)中,。最常見的就是使用哈希表,、B+樹作為索引。

一般的應(yīng)用系統(tǒng),,讀寫比例在10:1左右,,而且插入操作和一般的更新操作很少出現(xiàn)性能問題,在生產(chǎn)環(huán)境中,,我們遇到最多的,,也是最容易出問題的,還是一些復(fù)雜的查詢操作,,因此對查詢語句的優(yōu)化顯然是重中之重。說起加速查詢,,就不得不提到索引了,。

 

為什么要使用索引

我們知道,數(shù)據(jù)庫查詢是數(shù)據(jù)庫最主要的功能之一,。而查詢速度當(dāng)然是越快越好,。而當(dāng)數(shù)據(jù)量越來越大的時(shí)候,查詢花費(fèi)的時(shí)間會隨之增長,。而索引,,可以加速數(shù)據(jù)的查詢。因?yàn)樗饕怯行蚺帕械摹?/p>

舉個(gè)例子來說,,假設(shè)我們有一個(gè)數(shù)據(jù)庫表Employee,,這個(gè)表分別有三個(gè)字段:name,age,,address,。假設(shè)表中有1000條記錄,。

假如沒有使用索引,當(dāng)我們查詢名為“Jesus”的雇員的時(shí)候,,即調(diào)用:

select name,age,address from Employee where name = 'Jesus';

此時(shí)數(shù)據(jù)庫不得不在Employee表中對這1000條記錄一條一條的進(jìn)行判斷name字段是否為“Jesus”,。這也就是所謂的全表掃描。

而當(dāng)我們在Employee表上的name字段上創(chuàng)建索引時(shí),,當(dāng)我們查詢名為“Jesus”的雇員時(shí),,會通過索引查找去查詢名為“Jesus”的雇員,因?yàn)樵撍饕呀?jīng)按照字母順序排列,,因此要查找名為“Jesus”的記錄時(shí)會快很多,,因?yàn)槊质鬃帜笧椤癑”的雇員都是排列在一起的。通過該索引,,能獲取到表中對應(yīng)的記錄,。

舉例說明使用索引的好處

假設(shè)索引(索引是一種數(shù)據(jù)結(jié)構(gòu))是鏈表結(jié)構(gòu)。每個(gè)節(jié)點(diǎn)存儲的是關(guān)鍵字字段(這個(gè)例子中對應(yīng)的是name屬性)以及該關(guān)鍵字字段在數(shù)據(jù)庫表的對應(yīng)的記錄的地址,。而這些節(jié)點(diǎn)是根據(jù)name屬性排序的(即根據(jù)字母順序排序),。因此,當(dāng)我們執(zhí)行上面說的查找名為“Jesus”的sql語句時(shí),,數(shù)據(jù)庫會通過該索引來查詢,,因?yàn)樵撴湵硎怯行蚺帕械模谖覀冋业降谝粋€(gè)name屬性為“Jesus”的節(jié)點(diǎn)后,,繼續(xù)往后找,,當(dāng)遇到name屬性不為“Jesus”的節(jié)點(diǎn)時(shí),就無需再往后查找了,,因?yàn)楣?jié)點(diǎn)是根據(jù)name屬性有序排列的啊,。假設(shè)第一個(gè)name=“Jesus”的節(jié)點(diǎn)是第499個(gè)節(jié)點(diǎn),最后一個(gè)name=“Jesus”的節(jié)點(diǎn)是第500個(gè)節(jié)點(diǎn),,那么只需要遍歷501個(gè)節(jié)點(diǎn)就可以了,。當(dāng)發(fā)現(xiàn)第501個(gè)節(jié)點(diǎn)的name字段不為“Jesus”,后面的499個(gè)節(jié)點(diǎn)也就無需遍歷了,。通過索引,,我們就找到了name為“Jesus”的節(jié)點(diǎn),而通過該節(jié)點(diǎn)的另一個(gè)屬性(關(guān)鍵字字段在數(shù)據(jù)庫表的對應(yīng)的記錄的地址),,我們就能獲取到Employee表中滿足條件name=“Jesus”的記錄了,。

通過使用索引,查詢判斷的次數(shù)就從1000次縮小到了501次了,。起到了加速了查詢效率,。但實(shí)際上數(shù)據(jù)庫中索引的結(jié)構(gòu),并不是鏈表結(jié)構(gòu)。

數(shù)據(jù)庫中使用什么數(shù)據(jù)結(jié)構(gòu)作為索引

數(shù)據(jù)庫中實(shí)際使用的索引并不會是鏈表結(jié)構(gòu),,因?yàn)樾侍土恕?nbsp;
我們知道鏈表的查詢效率是O(n),。就像上面的例子,遍歷了501次才找到第一條符合條件的記錄,,這是很低效的,。而我們知道,數(shù)組+二分查找的效率是O(lgn),,但是數(shù)組的插入元素以及刪除元素的效率很低,,因此使用數(shù)組做為索引結(jié)構(gòu)并不合適。

另外,,在選擇數(shù)據(jù)庫索引的結(jié)構(gòu)的時(shí)候,,要考慮到另一個(gè)問題。索引是存在于磁盤中,,當(dāng)索引非常大的時(shí)候,,達(dá)到幾個(gè)G的時(shí)候,無法一次加載到內(nèi)存中,。

考慮到上面兩個(gè)因素,,數(shù)據(jù)庫中索引使用的是樹形結(jié)構(gòu)。

各種樹的名字

有這么幾種樹:

B-Tree
B+-Tree
B*-Tree

首先要明白三種樹名中的“-”起到的是分隔的作用,,并不是“減”的意思,。 

因此正確的翻譯應(yīng)該是B樹,B+樹,,B*樹,。而不是B-樹,B+樹,,B*樹,。因此,當(dāng)你聽到別人說“B減樹”的時(shí)候,,要明白它指的是B-Tree,。即B樹和B-樹是同一種樹。

為什么要強(qiáng)調(diào)上面這一點(diǎn)呢,,因?yàn)橛械牟┪闹袑懙氖牵築樹是二叉樹,B-樹是多路搜索樹,。

然而B樹和B-樹都是指B-Tree,。引用維基百科上的話:

B-tree 
Not to be confused with Binary tree.

 

也就是說,B-Tree并不是Binart tree,。B-Tree的中文名是平衡多路搜索樹,。 
(B樹的相關(guān)介紹在下面)

平衡二叉樹

樹形結(jié)構(gòu)是計(jì)算機(jī)系統(tǒng)里最重要的數(shù)據(jù)結(jié)構(gòu)。

我們知道,二叉樹的查找的時(shí)間復(fù)雜度是O(log2N),,其查找效率與深度有關(guān),,而普通的二叉樹可能由于內(nèi)部節(jié)點(diǎn)排列問題退化成鏈表,這樣查找效率就會很低,。因此平衡二叉樹是更好的選擇,,因?yàn)樗3制胶猓赐ㄟ^旋轉(zhuǎn)調(diào)整結(jié)構(gòu)保持最小的深度,。其查找的時(shí)間復(fù)雜度也是O(log2N),。

但實(shí)際上,數(shù)據(jù)庫中索引的結(jié)構(gòu)也并非AVL樹或更優(yōu)秀的紅黑樹,,盡管它的查詢的時(shí)間復(fù)雜度很低,。

為什么平衡二叉樹也不適合作為索引

之前說了平衡樹的查找時(shí)間復(fù)雜度是O(log2N),已經(jīng)很不錯(cuò)了,,但還是不適合作為索引結(jié)構(gòu),。那么肯定是有一種更適合作為索引的數(shù)據(jù)結(jié)構(gòu)。那么這個(gè)更適合作為索引的數(shù)據(jù)結(jié)構(gòu),,難道是查找的時(shí)間復(fù)雜度更低嗎,?并不是。這種作為索引的數(shù)據(jù)結(jié)構(gòu)的查找的時(shí)間復(fù)雜度也近似O(log2N),。

那為什么平衡二叉樹不適合作為索引呢,?

索引是存在于索引文件中,是存在于磁盤中的,。因?yàn)樗饕ǔJ呛艽蟮?,因此無法一次將全部索引加載到內(nèi)存當(dāng)中,因此每次只能從磁盤中讀取一個(gè)磁盤頁的數(shù)據(jù)到內(nèi)存中,。而這個(gè)磁盤的讀取的速度較內(nèi)存中的讀取速度而言是差了好幾個(gè)級別,。

注意,我們說的平衡二叉樹結(jié)構(gòu),,指的是邏輯結(jié)構(gòu)上的平衡二叉樹,,其物理實(shí)現(xiàn)是數(shù)組。然后由于在邏輯結(jié)構(gòu)上相近的節(jié)點(diǎn)在物理結(jié)構(gòu)上可能會差很遠(yuǎn),。因此,,每次讀取的磁盤頁的數(shù)據(jù)中有許多是用不上的。因此,,查找過程中要進(jìn)行許多次的磁盤讀取操作,。

而適合作為索引的結(jié)構(gòu)應(yīng)該是盡可能少的執(zhí)行磁盤IO操作,因?yàn)閳?zhí)行磁盤IO操作非常的耗時(shí),。因此,,平衡二叉樹并不適合作為索引結(jié)構(gòu),。

B-Tree適合作為索引

平衡二叉樹不適合作為索引。那么什么才適合作為索引——B樹,。

平衡二叉樹沒能充分利用磁盤預(yù)讀功能,,而B樹是為了充分利用磁盤預(yù)讀功能來而創(chuàng)建的一種數(shù)據(jù)結(jié)構(gòu),也就是說B樹就是為了作為索引才被發(fā)明出來的的,。

來看看關(guān)于“局部性原理與磁盤預(yù)讀”的知識: 

復(fù)制代碼
局部性原理與磁盤預(yù)讀:

由于存儲介質(zhì)的特性,,磁盤本身存取就比主存慢很多,再加上機(jī)械運(yùn)動耗費(fèi),,磁盤的存取速度往往是主存的幾百分分之一,,因此為了提高效率,要盡量減少磁盤I/O,。為了達(dá)到這個(gè)目的,,磁盤往往不是嚴(yán)格按需讀取,而是每次都會預(yù)讀,,即使只需要一個(gè)字節(jié),,磁盤也會從這個(gè)位置開始,順序向后讀取一定長度的數(shù)據(jù)放入內(nèi)存,。這樣做的理論依據(jù)是計(jì)算機(jī)科學(xué)中著名的局部性原理: 
當(dāng)一個(gè)數(shù)據(jù)被用到時(shí),,其附近的數(shù)據(jù)也通常會馬上被使用。 
程序運(yùn)行期間所需要的數(shù)據(jù)通常比較集中,。 
由于磁盤順序讀取的效率很高(不需要尋道時(shí)間,,只需很少的旋轉(zhuǎn)時(shí)間),因此對于具有局部性的程序來說,,預(yù)讀可以提高I/O效率,。
復(fù)制代碼

 

搞清楚上面的意思。磁盤預(yù)讀是具體實(shí)現(xiàn),,其理論依據(jù)是局部性原理,。

為什么說紅黑樹沒能充分利用磁盤預(yù)讀功能,引用一篇博文的一段話: 

紅黑樹這種結(jié)構(gòu),,h明顯要深的多,。由于邏輯上很近的節(jié)點(diǎn)(父子)物理上可能很遠(yuǎn),無法利用局部性,,所以紅黑樹的I/O漸進(jìn)復(fù)雜度也為O(h),,效率明顯比B-Tree差很多。

 

也就是說,,使用紅黑樹(平衡二叉樹)結(jié)構(gòu)的話,,每次磁盤預(yù)讀中的很多數(shù)據(jù)是用不上的數(shù)據(jù)。因此,,它沒能利用好磁盤預(yù)讀的提供的數(shù)據(jù),。然后又由于深度大(較B樹而言),所以進(jìn)行的磁盤IO操作更多,。

B樹的每個(gè)節(jié)點(diǎn)可以存儲多個(gè)關(guān)鍵字,,它將節(jié)點(diǎn)大小設(shè)置為磁盤頁的大小,充分利用了磁盤預(yù)讀的功能,。每次讀取磁盤頁時(shí)就會讀取一整個(gè)節(jié)點(diǎn),。也正因每個(gè)節(jié)點(diǎn)存儲著非常多個(gè)關(guān)鍵字,樹的深度就會非常的小,。進(jìn)而要執(zhí)行的磁盤讀取操作次數(shù)就會非常少,,更多的是在內(nèi)存中對讀取進(jìn)來的數(shù)據(jù)進(jìn)行查找。

B樹的查詢,,主要發(fā)生在內(nèi)存中,,而平衡二叉樹的查詢,則是發(fā)生在磁盤讀取中,。因此,,雖然B樹查詢查詢的次數(shù)不比平衡二叉樹的次數(shù)少,但是相比起磁盤IO速度,,內(nèi)存中比較的耗時(shí)就可以忽略不計(jì)了,。因此,B樹更適合作為索引,。

比B樹更適合作為索引的結(jié)構(gòu)——B+樹

比B樹更適合作為索引的結(jié)構(gòu)是B+樹,。MySQL中也是使用B+樹作為索引。它是B樹的變種,,因此是基于B樹來改進(jìn)的,。為什么B+樹會比B樹更加優(yōu)秀呢?

B樹:有序數(shù)組+平衡多叉樹,; 
B+樹:有序數(shù)組鏈表+平衡多叉樹,;

B+樹的關(guān)鍵字全部存放在葉子節(jié)點(diǎn)中,非葉子節(jié)點(diǎn)用來做索引,,而葉子節(jié)點(diǎn)中有一個(gè)指針指向一下個(gè)葉子節(jié)點(diǎn),。做這個(gè)優(yōu)化的目的是為了提高區(qū)間訪問的性能。而正是這個(gè)特性決定了B+樹更適合用來存儲外部數(shù)據(jù),。

引用一段話: 

復(fù)制代碼
走進(jìn)搜索引擎的作者梁斌老師針對B樹,、B+樹給出了他的意見(為了真實(shí)性,特引用其原話,,未作任何改動): “B+樹還有一個(gè)最大的好處,,方便掃庫,B樹必須用中序遍歷的方法按序掃庫,,而B+樹直接從葉子結(jié)點(diǎn)挨個(gè)掃一遍就完了,,B+樹支持range-query非常方便,,而B樹不支持。這是數(shù)據(jù)庫選用B+樹的最主要原因,。 
比如要查 5-10之間的,,B+樹一把到5這個(gè)標(biāo)記,再一把到10,,然后串起來就行了,,B樹就非常麻煩。B樹的好處,,就是成功查詢特別有利,,因?yàn)闃涞母叨瓤傮w要比B+樹矮。不成功的情況下,,B樹也比B+樹稍稍占一點(diǎn)點(diǎn)便宜,。 
B樹比如你的例子中查,17的話,,一把就得到結(jié)果了,, 
有很多基于頻率的搜索是選用B樹,越頻繁query的結(jié)點(diǎn)越往根上走,,前提是需要對query做統(tǒng)計(jì),,而且要對key做一些變化。 
另外B樹也好B+樹也好,,根或者上面幾層因?yàn)楸环磸?fù)query,,所以這幾塊基本都在內(nèi)存中,不會出現(xiàn)讀磁盤IO,,一般已啟動的時(shí)候,,就會主動換入內(nèi)存?!?/pre>
復(fù)制代碼

 

舉個(gè)例子來對比,。 
B樹: 

比如說,我們要查找關(guān)鍵字范圍在3到7的關(guān)鍵字,,在找到第一個(gè)符合條件的數(shù)字3后,,訪問完第一個(gè)關(guān)鍵字所在的塊后,得遍歷這個(gè)B樹,,獲取下一個(gè)塊,,直到遇到一個(gè)不符合條件的關(guān)鍵字。遍歷的過程是比較復(fù)雜的,。

B+樹(葉節(jié)點(diǎn)保存數(shù)據(jù),,其他的節(jié)點(diǎn) 全部存放索引): 

相比之下,B+樹的基于范圍的查詢簡潔很多,。由于葉子節(jié)點(diǎn)有指向下一個(gè)葉子節(jié)點(diǎn)的指針,,因此從塊1到塊2的訪問,,通過塊1指向塊2的指針即可。從塊2到塊3也是通過一個(gè)指針即可,。

引用一篇博文中網(wǎng)友評論的一段話: 

數(shù)據(jù)庫索引采用B+樹的主要原因是B樹在提高了磁盤IO性能的同時(shí)并沒有解決元素遍歷的效率低下的問題,。正是為了解決這個(gè)問題,B+樹應(yīng)運(yùn)而生,。
B+樹只要遍歷葉子節(jié)點(diǎn)就可以實(shí)現(xiàn)整棵樹的遍歷。而且在數(shù)據(jù)庫中基于范圍的查詢是非常頻繁的,,而B樹不支持這樣的操作(或者說效率太低),。

正如上面所說,在數(shù)據(jù)庫中基于范圍的查詢是非常頻繁的,,因此MySQL最終選擇的索引結(jié)構(gòu)是B+樹而不是B樹,。 

 

二、索引的原理

一 索引原理

索引的目的在于提高查詢效率,,與我們查閱圖書所用的目錄是一個(gè)道理:先定位到章,,然后定位到該章下的一個(gè)小節(jié),然后找到頁數(shù),。相似的例子還有:查字典,,查火車車次,飛機(jī)航班等

本質(zhì)都是:通過不斷地縮小想要獲取數(shù)據(jù)的范圍來篩選出最終想要的結(jié)果,,同時(shí)把隨機(jī)的事件變成順序的事件,,也就是說,有了這種索引機(jī)制,,我們可以總是用同一種查找方式來鎖定數(shù)據(jù),。

數(shù)據(jù)庫也是一樣,但顯然要復(fù)雜的多,,因?yàn)椴粌H面臨著等值查詢,,還有范圍查詢(>、<,、between,、in)、模糊查詢(like),、并集查詢(or)等等,。數(shù)據(jù)庫應(yīng)該選擇怎么樣的方式來應(yīng)對所有的問題呢?我們回想字典的例子,,能不能把數(shù)據(jù)分成段,,然后分段查詢呢?最簡單的如果1000條數(shù)據(jù),,1到100分成第一段,,101到200分成第二段,,201到300分成第三段......這樣查第250條數(shù)據(jù),只要找第三段就可以了,,一下子去除了90%的無效數(shù)據(jù),。但如果是1千萬的記錄呢,分成幾段比較好,?稍有算法基礎(chǔ)的同學(xué)會想到搜索樹,,其平均復(fù)雜度是lgN,具有不錯(cuò)的查詢性能,。但這里我們忽略了一個(gè)關(guān)鍵的問題,,復(fù)雜度模型是基于每次相同的操作成本來考慮的。而數(shù)據(jù)庫實(shí)現(xiàn)比較復(fù)雜,,一方面數(shù)據(jù)是保存在磁盤上的,,另外一方面為了提高性能,每次又可以把部分?jǐn)?shù)據(jù)讀入內(nèi)存來計(jì)算,,因?yàn)槲覀冎涝L問磁盤的成本大概是訪問內(nèi)存的十萬倍左右,,所以簡單的搜索樹難以滿足復(fù)雜的應(yīng)用場景。

 二 磁盤IO與預(yù)讀

考慮到磁盤IO是非常高昂的操作,,計(jì)算機(jī)操作系統(tǒng)做了一些優(yōu)化,,當(dāng)一次IO時(shí),不光把當(dāng)前磁盤地址的數(shù)據(jù),,而是把相鄰的數(shù)據(jù)也都讀取到內(nèi)存緩沖區(qū)內(nèi),,因?yàn)榫植款A(yù)讀性原理告訴我們,當(dāng)計(jì)算機(jī)訪問一個(gè)地址的數(shù)據(jù)的時(shí)候,,與其相鄰的數(shù)據(jù)也會很快被訪問到,。每一次IO讀取的數(shù)據(jù)我們稱之為一頁(page)。具體一頁有多大數(shù)據(jù)跟操作系統(tǒng)有關(guān),,一般為4k或8k,,也就是我們讀取一頁內(nèi)的數(shù)據(jù)時(shí)候,實(shí)際上才發(fā)生了一次IO,,這個(gè)理論對于索引的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)非常有幫助,。

三、索引的數(shù)據(jù)結(jié)構(gòu)

任何一種數(shù)據(jù)結(jié)構(gòu)都不是憑空產(chǎn)生的,,一定會有它的背景和使用場景,,我們現(xiàn)在總結(jié)一下,我們需要這種數(shù)據(jù)結(jié)構(gòu)能夠做些什么,,其實(shí)很簡單,,那就是:每次查找數(shù)據(jù)時(shí)把磁盤IO次數(shù)控制在一個(gè)很小的數(shù)量級,最好是常數(shù)數(shù)量級。那么我們就想到如果一個(gè)高度可控的多路搜索樹是否能滿足需求呢,?就這樣,,b+樹應(yīng)運(yùn)而生。

如上圖,,是一顆b+樹,,關(guān)于b+樹的定義可以參見B+樹,這里只說一些重點(diǎn),,淺藍(lán)色的塊我們稱之為一個(gè)磁盤塊,,可以看到每個(gè)磁盤塊包含幾個(gè)數(shù)據(jù)項(xiàng)(深藍(lán)色所示)和指針(黃色所示),如磁盤塊1包含數(shù)據(jù)項(xiàng)17和35,,包含指針P1,、P2、P3,,P1表示小于17的磁盤塊,P2表示在17和35之間的磁盤塊,,P3表示大于35的磁盤塊,。真實(shí)的數(shù)據(jù)存在于葉子節(jié)點(diǎn)即3、5,、9,、10、13,、15,、28、29,、36,、60、75,、79,、90、99,。非葉子節(jié)點(diǎn)只不存儲真實(shí)的數(shù)據(jù),,只存儲指引搜索方向的數(shù)據(jù)項(xiàng),如17,、35并不真實(shí)存在于數(shù)據(jù)表中,。

###b+樹的查找過程
如圖所示,如果要查找數(shù)據(jù)項(xiàng)29,,那么首先會把磁盤塊1由磁盤加載到內(nèi)存,,此時(shí)發(fā)生一次IO,在內(nèi)存中用二分查找確定29在17和35之間,鎖定磁盤塊1的P2指針,,內(nèi)存時(shí)間因?yàn)榉浅6蹋ㄏ啾却疟P的IO)可以忽略不計(jì),,通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內(nèi)存,發(fā)生第二次IO,,29在26和30之間,,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內(nèi)存,,發(fā)生第三次IO,,同時(shí)內(nèi)存中做二分查找找到29,結(jié)束查詢,,總計(jì)三次IO,。真實(shí)的情況是,3層的b+樹可以表示上百萬的數(shù)據(jù),,如果上百萬的數(shù)據(jù)查找只需要三次IO,,性能提高將是巨大的,如果沒有索引,,每個(gè)數(shù)據(jù)項(xiàng)都要發(fā)生一次IO,,那么總共需要百萬次的IO,顯然成本非常非常高,。

###b+樹性質(zhì)
1.索引字段要盡量的小:通過上面的分析,,我們知道IO次數(shù)取決于b+數(shù)的高度h,假設(shè)當(dāng)前數(shù)據(jù)表的數(shù)據(jù)為N,,每個(gè)磁盤塊的數(shù)據(jù)項(xiàng)的數(shù)量是m,,則有h=㏒(m+1)N,當(dāng)數(shù)據(jù)量N一定的情況下,,m越大,,h越小,;而m = 磁盤塊的大小 / 數(shù)據(jù)項(xiàng)的大小,,磁盤塊的大小也就是一個(gè)數(shù)據(jù)頁的大小,是固定的,,如果數(shù)據(jù)項(xiàng)占的空間越小,,數(shù)據(jù)項(xiàng)的數(shù)量越多,樹的高度越低,。這就是為什么每個(gè)數(shù)據(jù)項(xiàng),,即索引字段要盡量的小,比如int占4字節(jié),,要比bigint8字節(jié)少一半,。這也是為什么b+樹要求把真實(shí)的數(shù)據(jù)放到葉子節(jié)點(diǎn)而不是內(nèi)層節(jié)點(diǎn),,一旦放到內(nèi)層節(jié)點(diǎn),磁盤塊的數(shù)據(jù)項(xiàng)會大幅度下降,,導(dǎo)致樹增高,。當(dāng)數(shù)據(jù)項(xiàng)等于1時(shí)將會退化成線性表。
2.索引的最左匹配特性(即從左往右匹配):當(dāng)b+樹的數(shù)據(jù)項(xiàng)是復(fù)合的數(shù)據(jù)結(jié)構(gòu),,比如(name,age,sex)的時(shí)候,,b+數(shù)是按照從左到右的順序來建立搜索樹的,比如當(dāng)(張三,20,F)這樣的數(shù)據(jù)來檢索的時(shí)候,,b+樹會優(yōu)先比較name來確定下一步的所搜方向,,如果name相同再依次比較age和sex,最后得到檢索的數(shù)據(jù),;但當(dāng)(20,F)這樣的沒有name的數(shù)據(jù)來的時(shí)候,,b+樹就不知道下一步該查哪個(gè)節(jié)點(diǎn),因?yàn)榻⑺阉鳂涞臅r(shí)候name就是第一個(gè)比較因子,,必須要先根據(jù)name來搜索才能知道下一步去哪里查詢,。比如當(dāng)(張三,F)這樣的數(shù)據(jù)來檢索時(shí),b+樹可以用name來指定搜索方向,,但下一個(gè)字段age的缺失,,所以只能把名字等于張三的數(shù)據(jù)都找到,然后再匹配性別是F的數(shù)據(jù)了,, 這個(gè)是非常重要的性質(zhì),即索引的最左匹配特性,。

這也是經(jīng)??疾斓模热?我定義了 A,B,C的聯(lián)合索引,,如果 我只傳遞了 A,B 能走索引嗎,?答案是能,因?yàn)樽钭髠?cè)原理(百度問過) 

補(bǔ)充一下. 全文索引(FULLTEXT)=mysql的 myISAM搜索引擎默認(rèn)的索引類型

      MySQL從3.23.23版開始支持全文索引和全文檢索,,fulltext索引僅可用于 MyISAM 表,;他們可以從CHAR、VARCHAR或TEXT列中作為CREATE TABLE語句的一部分被創(chuàng)建,,或是隨后使用ALTER TABLE 或CREATE INDEX被添加,。////對于較大的數(shù)據(jù)集,將你的資料輸入一個(gè)沒有FULLTEXT索引的表中,,然后創(chuàng)建索引,,其速度比把資料輸入現(xiàn)有FULLTEXT索引的速度更為快。不過切記對于大容量的數(shù)據(jù)表,,生成全文索引是一個(gè)非常消耗時(shí)間非常消耗硬盤空間的做法,。
       文本字段上的普通索引只能加快對出現(xiàn)在字段內(nèi)容最前面的字符串(也就是字段內(nèi)容開頭的字符)進(jìn)行檢索操作。如果字段里存放的是由幾個(gè)、甚至是多個(gè)單詞構(gòu)成的較大段文字,,普通索引就沒什么作用了,。這種檢索往往以LIKE %word%的形式出現(xiàn),這對MySQL來說很復(fù)雜,,如果需要處理的數(shù)據(jù)量很大,,響應(yīng)時(shí)間就會很長。 
  這類場合正是全文索引(full-text index)可以大顯身手的地方,。在生成這種類型的索引時(shí),,MySQL將把在文本中出現(xiàn)的所有單詞創(chuàng)建為一份清單,查詢操作將根據(jù)這份清單去檢索有關(guān)的數(shù)據(jù)記錄,。全文索引即可以隨數(shù)據(jù)表一同創(chuàng)建,,也可以等日后有必要時(shí)再使用下面這條命令添加: 
  ALTER TABLE table_name ADD FULLTEXT(column1, column2) 
  有了全文索引,就可以用SELECT查詢命令去檢索那些包含著一個(gè)或多個(gè)給定單詞的數(shù)據(jù)記錄了,。下面是這類查詢命令的基本語法: 
  SELECT * FROM table_name 
  WHERE MATCH(column1, column2) AGAINST('word1', 'word2', 'word3') 
  上面這條命令將把column1和column2字段里有word1,、word2和word3的數(shù)據(jù)記錄全部查詢出來。 

參考:Mysql索引詳解及優(yōu)化(key和index區(qū)別) 

四,,索引使用注意事項(xiàng)

1,,不要濫用索引

①,索引提高查詢速度,,卻會降低更新表的速度,,因?yàn)楦卤頃r(shí),mysql不僅要更新數(shù)據(jù),,保存數(shù)據(jù),,還要更新索引,保存索引

②,,索引會占用磁盤空間 

2,,索引不會包含含有NULL值的列

復(fù)合索引只要有一列含有NULL值,那么這一列對于此符合索引就是無效的,因此我們在設(shè)計(jì)數(shù)據(jù)庫設(shè)計(jì)時(shí)不要讓字段的默認(rèn)值為NULL,。 

3,,MySQL查詢只是用一個(gè)索引

如果where字句中使用了索引的話,那么order by中的列是不會使用索引的 

4,,like

like '%aaa%'不會使用索引而like "aaa%"可以使用索引


二,、選擇索引的數(shù)據(jù)類型

Mysql支持很多數(shù)據(jù)類型,選擇合適的數(shù)據(jù)類型存儲數(shù)據(jù)對性能有很大的影響,。

(1)越小的數(shù)據(jù)類型通常更好:越小的數(shù)據(jù)類型通常在磁盤,、內(nèi)存和cpu緩存中都需要更少的空間,處理起來更快,。

(2)簡單的數(shù)據(jù)類型更好:整形數(shù)據(jù)比起字符,,處理開銷更小,,因?yàn)樽址谋容^更復(fù)雜。在MySQL中,,應(yīng)用內(nèi)置的日期和時(shí)間數(shù)據(jù)類型,,而不是字符串來存儲時(shí)間;以及用整形數(shù)據(jù)存儲IP地址,。

(3)盡量避免NULL:應(yīng)該制定列為NOT NULL,,除非你想存儲NULL。在MySQL中,,含有空值的列很難進(jìn)行查詢優(yōu)化,,因?yàn)樗麄兪沟盟饕⑺饕慕y(tǒng)計(jì)信息以及比較運(yùn)算更加復(fù)雜,。

三,、MySQL常見索引有:主鍵索引、唯一索引,、普通索引,、全文索引、組合索引

1,,INDEX(普通索引):ALTER TABLE 'table_name' ADD INDEX index_name('col')

最基本的索引,,沒有任何限制 

2,UNIQUE(唯一索引):ALTER TABLE 'table_name' ADD UNIQUE('col')

與“普通索引”類似,,不同的就是:索引列的值必須唯一,,但允許有空值。 

3,,PRIMARY KEY(主鍵索引):ALTER TABLE 'table_name' ADD PRIMARY KEY('col')

是一種特殊的唯一索引,,不允許有空值。 

4,,F(xiàn)ULLTEXT(全文索引):ALTER TABLE 'table_name' ADD FULLTEXT('col')

僅可用于MyISAM和InoDB,針對較大的數(shù)據(jù),,生成全文索引很耗時(shí)耗空間

組合索引:ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3')

為了更多的提高mysql效率可建立組合索引,,遵循“最左前綴”原則。創(chuàng)建復(fù)合索引應(yīng)該將最常用(頻率)做限制條件的列放在最左邊,,一次遞減,。組合索引最左字段用in是可以用到索引的。相當(dāng)于建立了col1,col1col2,col1col2col3三個(gè)索引

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多