Btree索引和Hash索引
生活随笔
收集整理的這篇文章主要介紹了
Btree索引和Hash索引
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
索引對(duì)于數(shù)據(jù)庫(kù)性能的影響,非常的關(guān)鍵,索引的主要作用呢是告訴存儲(chǔ)引擎,如何快速的找到我們所需要的數(shù)據(jù),當(dāng)表中的數(shù)據(jù)比較少時(shí),查詢的頻率也比較低的情況下,索引的作用呢可能還不是太明顯,因?yàn)檫@個(gè)時(shí)候呢,表中的數(shù)據(jù),差不多完全可以緩存到內(nèi)存中,所以就算是進(jìn)行全表掃描,也不會(huì)太慢,而隨著表中數(shù)據(jù)越來(lái)越多,查詢頻率也越來(lái)越高,內(nèi)存已經(jīng)不能完全緩存數(shù)據(jù)的時(shí)候,索引的作用就顯得越來(lái)越重要,在實(shí)際的工作中,發(fā)現(xiàn)人們總是忽略,或者是過(guò)分強(qiáng)調(diào)索引的作用,所以會(huì)有兩種極端的表現(xiàn),一種是表中除了主鍵外,沒有任何的索引,另一種是給表中的每一列,建立一個(gè)索引,這兩種做法都是不正確的,太多的或者太少的索引呢,都會(huì)對(duì)數(shù)據(jù)庫(kù)的性能帶來(lái)不好的影響,只有在正確的列上建立正確的索引的情況下,才能增強(qiáng)數(shù)據(jù)庫(kù)的處理能力,為了能夠正確的使用索引,我們先看看MYSQL支持的索引類型有哪些,剛才我們提到了,索引的主要作用呢,其實(shí)就是告訴存儲(chǔ)引擎,如何快速找到我們所需要的數(shù)據(jù),所以說(shuō)呢,MYSQL的索引呢,是在存儲(chǔ)引擎層來(lái)實(shí)現(xiàn)的,而不是在MYSQL的服務(wù)器層來(lái)實(shí)現(xiàn)的,這就決定了不同的存儲(chǔ)引擎,他的索引呢,可能用的方式是不同的,同時(shí)也不是所有的存儲(chǔ)引擎,都會(huì)支持所有的索引類型,即使是同一種類型的索引,在不同的存儲(chǔ)引擎上,其底層的實(shí)現(xiàn)呢,是不相同,現(xiàn)在我們先來(lái)看看MYSQL支持的索引類型,以及他們的優(yōu)缺點(diǎn),B樹索引呢,是最常見的一種索引類型,通常我們所說(shuō)的索引呢,就指的B樹索引,它使用的是B+樹的結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù),在B+樹中,每一個(gè)葉子節(jié)點(diǎn)呢,都包含指向下一個(gè)節(jié)點(diǎn)的指針,這樣可以方便的進(jìn)行葉子節(jié)點(diǎn)的遍歷,下面我們就來(lái)看看B樹節(jié)點(diǎn)的一些特點(diǎn),首先第一個(gè)特點(diǎn)就是我們已經(jīng)說(shuō)過(guò)了的,B樹索引是以B+的結(jié)構(gòu)呢,存儲(chǔ)數(shù)據(jù)的,對(duì)于不熟悉數(shù)據(jù)結(jié)構(gòu)的來(lái)說(shuō)呢,可能不明白什么是B+樹,那下面我們就簡(jiǎn)單的圖示呢來(lái)給大家講解一下,B+樹的存儲(chǔ)結(jié)構(gòu)是什么樣子的,從這張圖中我們可以看到
B+樹是一種平衡的查找樹,每一個(gè)葉子到根部的距離呢,是相同的,并且所有的節(jié)點(diǎn)呢,都是按照鍵值的大小來(lái)順序存放的,同一層葉子節(jié)點(diǎn)上的,并且各個(gè)葉子節(jié)點(diǎn)呢,使用指針來(lái)互相連接的,前面說(shuō)到了,這樣做的好處呢,是可以方便的快速進(jìn)行查找,這就是典型的B樹索引的存儲(chǔ)結(jié)構(gòu),但是對(duì)于不同存儲(chǔ)引擎來(lái)說(shuō),具體的實(shí)現(xiàn)呢可能會(huì)有不同,比如說(shuō)MYISAM索引呢,在葉子節(jié)點(diǎn)上呢,通過(guò)數(shù)據(jù)的物理位置,來(lái)進(jìn)行引用行的,而innodb呢,則是通過(guò)組建,來(lái)引用索引的行的,我們接下來(lái)看一下索引的其他一些特點(diǎn),從前面的圖示中可以看到,B樹索引呢,是可以加快存儲(chǔ)引擎查找速度的,通常情況下,索引的大小呢,遠(yuǎn)小于表中數(shù)據(jù)的大小,使用了B樹索引存儲(chǔ)引擎呢,存儲(chǔ)引擎就不再需要全表掃描,來(lái)獲取需要的數(shù)據(jù)了,取而代之的呢就是從,從索引的根節(jié)點(diǎn)進(jìn)行搜索,在索引的根節(jié)點(diǎn)中,存放了指向下層節(jié)點(diǎn)的指針,存儲(chǔ)引擎呢,根據(jù)這些指針向下層進(jìn)行查找,通過(guò)比較節(jié)點(diǎn)頁(yè)的值,和要查找的值呢,就可以得到,合適的指針,進(jìn)入下層的子節(jié)點(diǎn),而這些指針呢,實(shí)際上是定義了子節(jié)點(diǎn)中值的上限和下限,所以最終存儲(chǔ)引擎呢,要找到對(duì)應(yīng)的值呢,就可以確定,所查找的數(shù)據(jù)是不存在的,最終存儲(chǔ)引擎是通過(guò)B樹索引找到符合要求的葉子節(jié)點(diǎn),葉子節(jié)點(diǎn)比較特別,他的指針是指向被索引的數(shù)據(jù),而不是其他的葉子節(jié)點(diǎn),前面說(shuō)過(guò)了,在innodb存儲(chǔ)引擎中呢,葉子節(jié)點(diǎn)指向的是主鍵,而在MYISAM中呢,葉子節(jié)點(diǎn)指向的是物理地址,另外,由于B樹索引呢,對(duì)索引是順序存儲(chǔ)的,所以B樹索引的最后一個(gè)特點(diǎn)呢,就是他很適合進(jìn)行范圍查找,這一點(diǎn)和后面的hash索引有很大的不同
每當(dāng)我們建立索引的時(shí)候呢,就希望查詢呢可以向我們所想象的那樣來(lái)使用這個(gè)索引,但是實(shí)際情況呢,MYSQL并不像我們所希望的那樣,使用我們所建立的索引,那么這其中有很多原因,下面我們就來(lái)看看B樹索引呢,在什么情況下才能被使用到,第一種使用B樹索引的查詢呢,是全局匹配的查詢,那么全職匹配的呢,是指和索引中的所有列,來(lái)進(jìn)行匹配,比如下面的過(guò)濾條件,如果我們?cè)谟唵翁?hào),order_sn上建立了一個(gè)B樹索引,這時(shí)我們就要查找,訂單為9876這樣的一個(gè)訂單,這樣就是進(jìn)行一個(gè)全局匹配的一個(gè)查詢,那么第二種可以使用到B樹的查詢呢,就是匹配最左前綴的查詢,還以前面的查詢?yōu)槔?我們?cè)趏rder_sn列上,并沒有建立索引,而是建立了一個(gè)order_sn和order_date兩個(gè)列,也就是訂單號(hào)和訂單日期,這兩個(gè)列上的聯(lián)合索引,對(duì)于上面的查詢條件呢,是可以利用聯(lián)合索引的,也就是說(shuō),只要聯(lián)合索引的第一列,符合查詢條件,這個(gè)索引就會(huì)被用到,但是如何只是這個(gè)聯(lián)合索引的第二列符合查詢條件,比如說(shuō),查詢所有order_date等于2016年1月1號(hào)的訂單,這樣的查找條件呢,是無(wú)法利用到聯(lián)合索引的,這個(gè)就叫做最左前綴的查詢,那么第三種可以利用的查詢呢,是匹配列前綴的查詢,那么匹配列前綴和最左前綴呢,是不同的,匹配列前綴呢,是可以匹配某一列的開頭部分,比如下面這個(gè)查詢條件,查詢所有以9876開頭的訂單號(hào),這個(gè)查詢也可以利用到前面所說(shuō)的order_sn列開頭的聯(lián)合索引
前面提到過(guò),由于B樹索引的存儲(chǔ)特點(diǎn)呢,所以B樹索引的更適合的是范圍查找,比如下面這個(gè)查找,就可以利用到B樹索引,我們可以查到訂單號(hào),大于某一個(gè)訂單號(hào)的訂單,或者某一個(gè)訂單號(hào)在某一個(gè)區(qū)間的訂單,都是一個(gè)范圍查找,我們很少會(huì)使用到訂單號(hào)查找,只是給大家舉個(gè)例子,那么另外呢,B樹索引呢,還可以精確的匹配左前列,并范圍匹配另外一列這樣的查找,以前面所定義的order_sn和order_date兩個(gè)聯(lián)合索引來(lái)說(shuō)呢,就是說(shuō),索引可以精確匹配order_sn列,和訂單日期列呢,一個(gè)范圍內(nèi)的一種查詢,最后B樹索引呢還可以使用在只訪問(wèn)索引那種查詢上,這種索引就稱之為覆蓋索引,也就是查詢只需要訪問(wèn)索引,而無(wú)需訪問(wèn)數(shù)據(jù)行,這種查詢的效率也是非常高的,以上呢就是B樹索引,可以使用的一些場(chǎng)景,B樹索引除了可以使用在查詢過(guò)濾之外呢,還可以使用在ORDER BY程序中,因?yàn)锽樹索引是按順序來(lái)存儲(chǔ)的,所以B樹索引是按照某種方式來(lái)查找到值,同樣也可以按照這種方式來(lái)對(duì)數(shù)據(jù)進(jìn)行排序,要全面的了解B樹索引呢,我們還要看看在使用B樹索引時(shí)呢,是有什么樣的限制的,下面我們就來(lái)看看B樹索引的一些限制
下面我們就來(lái)看看B樹索引的一些限制,我們?cè)谄匠5墓ぷ髦?經(jīng)常會(huì)遇到,明明在查詢過(guò)濾條件上建立索引,但是查詢卻無(wú)法使用到索引的這種情況,這和很多因素是有關(guān)的,比如說(shuō)使用索引,所命中的數(shù)據(jù)呢,如果占用表中大部分?jǐn)?shù)據(jù)時(shí),MYSQL的查詢優(yōu)化器會(huì)認(rèn)為,使用全表掃描的方式呢,會(huì)性能更好,所以就不會(huì)使用索引的方式來(lái)進(jìn)行查詢了,此外在使用B樹索引時(shí)呢,還會(huì)有一些限制,如果是按照受限制的方式來(lái)使用索引的話,則同樣不會(huì)用到相同位置的索引,下面我們就來(lái)看看這些限制有哪些,首先使用B樹索引的第一個(gè)限制是,如果我們不是按照索引的最左列進(jìn)行查找的,則無(wú)法使用到索引,還拿我們之前的訂單號(hào)和訂單日期所建立的聯(lián)合索引為例,如果索引的順序是先訂單號(hào),后是訂單日期,也就是說(shuō),訂單號(hào)是最左列,而如果我們?cè)诓樵冎心?只通過(guò)訂單日期列來(lái)作為查詢條件呢,就無(wú)法使用到在訂單號(hào)和訂單日期上的聯(lián)合索引,另外在使用B樹索引時(shí)呢,也不能跳過(guò)索引中左邊的列,而使用索引,這種情況呢,和上面De情況稍微有點(diǎn)不同,這里說(shuō)的是左邊的列,而不是最左邊的列,一個(gè)以三列所組成的聯(lián)合索引為例,來(lái)給大家講解一下其中的不同之處,加入我們由訂單日期,下單人的姓名,和下單人的電話,所組成的聯(lián)合索引,如果我們?cè)诓檎抑心?包括了訂單日期,和下單人的電話,那么對(duì)于這個(gè)查詢來(lái)說(shuō)呢,只能使用訂單日期這一列來(lái)進(jìn)行查詢過(guò)濾,而無(wú)法使用到下單人電話這一列,這是因?yàn)槲覀兊牟樵儣l件中,跳過(guò)了下單人姓名這一列,而且通常來(lái)說(shuō),對(duì)通過(guò)使用索引來(lái)進(jìn)行使用not in,和不等于過(guò)濾條件的查詢呢,也是無(wú)法使用到索引的,最后在使用B樹索引時(shí)呢,請(qǐng)注意,如果查詢中使用了索引中某個(gè)列的范圍查詢,則在這個(gè)索引中,這個(gè)使用范圍查詢的所有列呢,都無(wú)法使用索引來(lái)進(jìn)行查找了,以上就是使用B樹索引的一些限制,限制我們已經(jīng)了解了B樹索引的存儲(chǔ)結(jié)構(gòu),使用范圍和使用的限制,那么下面我們?cè)賮?lái)看看另外一種在MYSQL中,比較常用的索引,hash索引的一些特點(diǎn)
在MYSQL的一些存儲(chǔ)引擎中,除了B樹索引以外,還有支持Hash索引的存儲(chǔ)引擎,比如我們?cè)诮榻B存儲(chǔ)引擎的時(shí)候就說(shuō)過(guò),memory存儲(chǔ)引擎就是支持hash和b樹這兩種索引的存儲(chǔ)引擎,并且呢在默認(rèn)情況下,memory存儲(chǔ)引擎呢,我們還是hash索引,另外innodb呢,也支持hash索引,不過(guò)innodb的hash索引呢不是我們自己來(lái)建立的,而是innodb存儲(chǔ)引擎呢根據(jù)B樹索引使用的一種使用情況呢,來(lái)自行建立的,所以也稱之為自適應(yīng)哈希索引,下面我們來(lái)看看哈希索引有哪些特點(diǎn),首先哈希索引是基于哈希表來(lái)實(shí)現(xiàn)的,只有查詢條件精確匹配,hash索引中所有的列時(shí),才能夠使用到哈希索引,也就是說(shuō),哈希索引只能用到等值查詢中,如果我們要進(jìn)行范圍查詢,或者模糊查詢的話呢,就不能使用到哈希索引了,另外呢存儲(chǔ)引擎對(duì)哈希索引所包含的所有的列呢,都會(huì)為每一行計(jì)算一個(gè)hash碼,hash碼通常都會(huì)比較小,并且不同鍵值的行呢,hash碼通常是不一樣的,哈希索引中呢,存儲(chǔ)的就是這個(gè)哈希碼,所以就解釋了哈希索引只能支持這種全局匹配的查詢了,因?yàn)橹挥羞@樣哈希才能匹配,同時(shí)在哈希索引的表中呢,還保存了每一個(gè)哈希索引,所代表的數(shù)據(jù)行的指針,由于哈希索引呢,本身只存儲(chǔ)了,哈希碼,所以哈希索引的存儲(chǔ)結(jié)構(gòu)呢,十分緊湊的,這也使得哈希索引呢找到數(shù)據(jù)的速度會(huì)非常快,但是呢,哈希索引也存在一些限制,下面我們就來(lái)看看這些限制
下面我們就來(lái)看看這些限制,首先使用哈希索引查找數(shù)據(jù)呢,必須進(jìn)行兩次讀取,前面我們說(shuō)過(guò)了,哈希索引包括的只是鍵值和哈希碼,以及對(duì)應(yīng)的行的指針,索引中并沒有保存字段的值,所以在使用哈希索引時(shí),必須通過(guò)哈希索引找到對(duì)應(yīng)的行,然后對(duì)行的記錄進(jìn)行讀取,所以呢,如果使用哈希索引的話,是需要進(jìn)行兩次查找的,不過(guò)呢,無(wú)論是memory存儲(chǔ)引擎,還是innodb中頻繁被訪問(wèn)到的行,基本上都是緩存在內(nèi)存中的,而對(duì)于內(nèi)存中的行呢,數(shù)據(jù)訪問(wèn)的速度會(huì)非常的快,所以大部分情況下,這一部分對(duì)性能的影響不會(huì)太明顯,第二點(diǎn)呢,是因?yàn)楣K饕?是按照哈希碼的順序來(lái)進(jìn)行存儲(chǔ)的,而不是按照鍵值的順序來(lái)存儲(chǔ)的,所以就沒有辦法像B樹索引那樣,來(lái)進(jìn)行查詢結(jié)果的排序操作,對(duì)于哈希索引的第三個(gè)限制,我們剛才在講解哈希索引的存儲(chǔ)結(jié)構(gòu)時(shí)呢,已經(jīng)提到過(guò)了,那就是哈希索引呢,只可以進(jìn)行全鍵值的匹配查找,而不支持部分鍵值的匹配查找,同時(shí)也不支持鍵值的范圍查找,這也是哈希索引,存儲(chǔ)特點(diǎn)所決定的,因?yàn)槲覀儫o(wú)法把一個(gè)范圍值或者具體的哈希碼來(lái)匹配,所以也就不能進(jìn)行這樣的查詢了,最后哈希索引在計(jì)算哈希碼時(shí)呢,是有可能發(fā)生哈希沖突的,所謂的哈希沖突呢,也就是不同的索引列呢,他計(jì)算的哈希碼呢,是相同的,那么對(duì)于經(jīng)常使用哈希函數(shù)的人來(lái)說(shuō)呢,可以知道,這種情況是無(wú)法避免的,特別是為了保證哈希索引的查詢效率,哈希碼通常都比較小,就算是md5這樣的哈希值呢,也是有可能存在沖突的,在哈希索引中呢,一旦產(chǎn)生大量的哈希沖突,就會(huì)影響哈希索引的查找,和維護(hù)的性能,所以哈希索引不適合用在選擇性很差的列上,選擇性差也就是說(shuō),鍵值列的重復(fù)值很多,比如性別這樣的列,不管有多少行數(shù)據(jù),只有兩種可選擇值,所以選擇性就很差,這樣的列上是不可以使用哈希索引的,再比如身份證列,大家知道,身份證的重復(fù)概率呢,是很小的,所以在這一列上建立哈希索引就很合適,哈希索引和B樹索引呢,是MYSQL中最常用的兩種索引類型,索引優(yōu)化也是針對(duì)這兩種索引來(lái)進(jìn)行的,那么在進(jìn)行具體的索引優(yōu)化策略之前呢,我們還要明確兩個(gè)概念,一個(gè)是我們?yōu)槭裁匆褂盟饕?也就是說(shuō),使用索引能給我們帶來(lái)哪些好處,另一個(gè)是索引是不是越多性能就越好
使用索引可以讓我們快速的定位到我們所需要的數(shù)據(jù),但是這并不是索引的唯一作用,前面我們?cè)诮榻BB樹索引時(shí)呢,提到過(guò),B樹索引呢,索引的鍵值是按順序來(lái)存儲(chǔ)的,所以我們還可以利用B樹索引來(lái)order by,或者group by這樣的操作,我們來(lái)說(shuō),使用索引呢,可以給我們帶來(lái)三個(gè)好處,首先索引呢,可以大大的減少存儲(chǔ)引擎需要掃描的數(shù)據(jù)的數(shù)量,索引文件的大小呢,通常會(huì)遠(yuǎn)遠(yuǎn)小于數(shù)據(jù)的大小,以innodb來(lái)說(shuō),innodb存儲(chǔ)引擎呢,發(fā)生一次IO,那么最小的是存取單位呢,是以頁(yè)來(lái)為單位的,所以一頁(yè)內(nèi)可以存儲(chǔ)的信息越多,那么他的這種讀取效率也就越快,默認(rèn)情況下呢,innodb的大小為16K,由于索引的大小,通常要比一行的大小要小的多,所以一頁(yè)內(nèi)可以存儲(chǔ)更多的索引的數(shù)據(jù),因此通過(guò)索引,來(lái)進(jìn)行查找的話呢,所需要讀取頁(yè)的數(shù)量呢,也就會(huì)越少,這樣也就減少了存儲(chǔ)引擎,需要掃描的數(shù)據(jù)的數(shù)量,加快了數(shù)據(jù)的查找的速度,另外由于B樹索引是按鍵值的順序存放的,所以我們要利用B樹索引來(lái)進(jìn)行排序,這樣就避免了使用排序IO消耗,同時(shí)也提高了MYSQL的處理的能力,最后由于B樹索引的鍵值是按順序存放的,而數(shù)據(jù)行的物理地址呢,通常是隨機(jī)分布的,所以使用索引進(jìn)行查找呢,是可以把這種隨機(jī)的IO呢,整為順序的IO的,這樣可以更加充分的發(fā)揮磁盤的IO性能
那么在現(xiàn)實(shí)的工作中呢,經(jīng)常有人喜歡,給表加上read索引,而不管這個(gè)索引是否有用,他們會(huì)認(rèn)為,索引可以加快數(shù)據(jù)查找的效率,所以即使是現(xiàn)在用不到,那么給列上加上一些索引呢,也是沒有壞處的,前不久我剛剛遇到過(guò),這樣一種情況,他要求非常急切的在一張表上,加上一些索引,那么我就問(wèn)他們?yōu)槭裁匆由线@些索引呢,得到的回答是,是因?yàn)檫@個(gè)表中,導(dǎo)入數(shù)據(jù)的時(shí)候呢,很慢,所以他們希望,增加一些索引,以加快數(shù)據(jù)的導(dǎo)入速度,由此可見開發(fā)人員對(duì)于索引是存在很大的誤解的,大家不要奇怪,現(xiàn)實(shí)中這樣的例子并不少見,索引雖然可以加快查找的速度,但是也會(huì)給我們的性能帶來(lái)一定的損耗,只有索引幫助存儲(chǔ)引擎快速查找到所帶來(lái)的好處,要大于其所帶來(lái)的消耗時(shí)的索引才是有效地,那我們來(lái)看看索引會(huì)給我們的性能帶來(lái)哪些損耗,首先索引,會(huì)增加數(shù)據(jù)庫(kù)寫入的成本,由于我們?cè)谶M(jìn)行數(shù)據(jù)更新,插入,必須要同時(shí)呢,對(duì)相關(guān)的索引和統(tǒng)計(jì)信息,進(jìn)行維護(hù),所以呢,索引越多,修改數(shù)據(jù)所需要的時(shí)間呢,就會(huì)越長(zhǎng),為了解決這個(gè)問(wèn)題呢,innodb引入了一個(gè)插入緩存,把多次插入操作,合并成一次,所以說(shuō),我們一開始就說(shuō)到的,開發(fā)人員想增加索引,以加快數(shù)據(jù)的導(dǎo)入速度,是絕對(duì)錯(cuò)誤的,想增加數(shù)據(jù)導(dǎo)入的最好做法呢,是把所有的索引,全部刪除掉,當(dāng)然了,對(duì)于innodb而言呢,至少要保留一個(gè)自增的ID主鍵,否則插入性能會(huì)更差,通常來(lái)說(shuō),大多數(shù)人都知道,索引對(duì)數(shù)據(jù)庫(kù)的寫操作,造成的一種性能的影響,可能很少人會(huì)知道,過(guò)多的索引同樣也會(huì)影響數(shù)據(jù)庫(kù)查詢的性能,因?yàn)镸YSQL的查詢優(yōu)化器呢,會(huì)根據(jù)索引的統(tǒng)計(jì)信息,和查詢的條件,來(lái)為查詢選擇合適的索引,如果對(duì)于一個(gè)查詢有很多的索引,對(duì)可以使用,則會(huì)增加MYSQL查詢優(yōu)化器對(duì)于查詢的時(shí)間,從而也會(huì)影響數(shù)據(jù)庫(kù)的查詢效率,可見太多的索引呢,無(wú)論是對(duì)寫操作,還是對(duì)讀操作來(lái)說(shuō),都是沒有什么好處的,只有在適當(dāng)?shù)牧猩辖⑦m當(dāng)?shù)乃饕?這個(gè)時(shí)候索引才能提高數(shù)據(jù)庫(kù)的性能,下面我們就來(lái)看看建立索引的一些策略
?
總結(jié)
以上是生活随笔為你收集整理的Btree索引和Hash索引的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SpringMVC中向服务器传输数据(解
- 下一篇: 索引优化策略(上)