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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

数据结构与索引-- B+树索引

發(fā)布時(shí)間:2023/12/4 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构与索引-- B+树索引 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

B+樹索引

  • 上一節(jié)中我們討論的都是B+樹的數(shù)據(jù)結(jié)構(gòu)的由來以及他的一些操作,B+樹索引在本質(zhì)就是B+樹在數(shù)據(jù)庫(kù)中的一個(gè)實(shí)現(xiàn),但是B+索引在數(shù)據(jù)庫(kù)中有一個(gè)特點(diǎn)就是他的高扇出性,因此在數(shù)據(jù)庫(kù)中,B+樹的高度一般是2~3層,也就是對(duì)于查找某一個(gè)鍵值的行記錄,最多只需要2 ~ 3次IO,我們假設(shè)一般的磁盤每秒可以做100次IO,那么2 ~3次就差不多0.02 秒 ~0.03秒

    • 扇入數(shù)(引入)就是引入了多少別的模塊引到自己模塊來,像光線匯聚。
    • 扇出(輸出)就是自己模塊被多少個(gè)其他模塊拿來使用,像瀑布鋪灑。
    • 用如下圖解釋
  • 數(shù)據(jù)庫(kù)中的B+樹索引分為聚集索引(clustered index)和輔助索引(secondary index),但是不管是聚集索引還是輔助索引,內(nèi)部結(jié)構(gòu)都是B+樹,即高度平衡的,葉節(jié)點(diǎn)存放著所有的數(shù)據(jù),聚集索引與非聚集索引不同的是,葉子節(jié)點(diǎn)存放的是否是一整行的信息

聚集索引

  • InnoDB存儲(chǔ)引擎表是索引組織表,即表中數(shù)據(jù)依照主鍵順序存放。而聚集索引就是按照每張表的主鍵構(gòu)造一顆B+樹,并且葉子節(jié)點(diǎn)存放整張表的行為記錄數(shù)據(jù),因此也讓聚集索引的葉節(jié)點(diǎn)成為數(shù)據(jù)頁(yè)。聚集索引的這個(gè)特性決定了索引組織表中數(shù)據(jù)也是索引的一部分。和B+樹數(shù)據(jù)結(jié)構(gòu)一樣,每一個(gè)數(shù)據(jù)頁(yè)都通過一個(gè)雙向鏈表來進(jìn)行連接

  • 由于實(shí)際的數(shù)據(jù)頁(yè)只能按照一顆B+樹進(jìn)行排序,因此每張表只擁有一個(gè)聚集索引。在許多情況下,查詢優(yōu)化器非常傾向于采用聚集索引,因此,聚集索引能夠讓我們?cè)谒饕娜~子節(jié)點(diǎn)上直接找到數(shù)據(jù)。此外,由于定義了數(shù)據(jù)的邏輯順序,聚集索引能夠特別快的訪問針對(duì)范圍的查詢。查詢優(yōu)化器能夠快速發(fā)現(xiàn)某一段范圍的數(shù)據(jù)頁(yè)需要進(jìn)一步掃描篩選數(shù)據(jù)。

  • 我們用如下的表以及數(shù)據(jù)來說明,我們以認(rèn)為的方式讓每一個(gè)頁(yè)只能存放兩個(gè)行為記錄:

create table t(a int not null primary key, b varchar(8000))insert into t select 1, repeat('a', 7000);insert into t select 2, repeat('a', 7000);insert into t select 3, repeat('a', 7000);insert into t select 4, repeat('a', 7000);
  • 我們?nèi)缟媳淼亩x,插入的數(shù)據(jù)使得目前每個(gè)頁(yè)只能存放兩個(gè)行記錄,并且在構(gòu)造的B+樹上,數(shù)據(jù)頁(yè)上存放的是完整的行記錄,而在非數(shù)據(jù)頁(yè)的索引頁(yè)中,存放的僅僅是鍵值以及指向數(shù)據(jù)頁(yè)的偏移量,而不是一個(gè)完整的行記錄,因此我們構(gòu)造這顆二叉樹大致如下圖:

  • 很多數(shù)據(jù)庫(kù)文檔中說過,聚集索引按照順序物理的存儲(chǔ)數(shù)據(jù)。如上圖可以看到會(huì)有這種感覺。但是,如果聚集索引必須按照特定順序存放物理記錄的話,則維護(hù)成本會(huì)非常高。索引,聚集索引的存儲(chǔ)并不是物理上連續(xù)的,相反,邏輯上才是連續(xù)的。有兩點(diǎn):

    • 一個(gè)是我們說過頁(yè)面通過雙向鏈表鏈接,頁(yè)按照主鍵順序排列
    • 每個(gè)頁(yè)中的記錄也是通過雙向鏈表進(jìn)行維護(hù),物理存儲(chǔ)上可以同樣不按主鍵存儲(chǔ)。
  • 聚集索引的一個(gè)好處是,他對(duì)于主鍵的排序查找和范圍查找速度非常快。葉節(jié)點(diǎn)的數(shù)據(jù)就是我們要查詢的數(shù)據(jù),如果我們要查詢一張注冊(cè)用戶的表,查詢最后注冊(cè)的10位用戶,由于B+樹索引是雙向的,我們可以快速找到最后一個(gè)數(shù)據(jù)頁(yè),并去除10條記錄,我們用explain分析如下:

EXPLAIN select * from moment order by id limit 10

  • 另一個(gè)是范圍查找(range query),如果查找主鍵某個(gè)范圍內(nèi)的數(shù)據(jù),通過葉節(jié)點(diǎn)的上層中間節(jié)點(diǎn)就可以得到頁(yè)的范圍,之后直接讀取數(shù)據(jù)頁(yè)即可,如下:
EXPLAIN select * from moment where id > 1590 and id < 20000

  • 上圖中的rows代表是一個(gè)預(yù)估值,,如果實(shí)際查詢這條sql的數(shù)據(jù)條數(shù)發(fā)現(xiàn)更多17384條。

輔助索引

  • 對(duì)應(yīng)輔助索引,也就是我們說的***非聚集索引***,葉節(jié)點(diǎn)不包含行的全部數(shù)據(jù)。葉子節(jié)點(diǎn)除了包含鍵值以外,每個(gè)葉子節(jié)點(diǎn)中的索引行中還包含了一個(gè)書簽(bookmark),該書簽用來告訴InnoDB存儲(chǔ)引擎,哪里可以找到與索引對(duì)應(yīng)的行數(shù)據(jù)。因?yàn)镮nooDB存儲(chǔ)引擎表是索引組織表,因此,InnoDB存儲(chǔ)引擎的輔助索引的書簽就是相應(yīng)數(shù)據(jù)的聚集索引的鍵值。如下圖表示InnoDB存儲(chǔ)引擎中輔助索引與聚集索引的關(guān)系。

  • 輔助索引的存在并不影響數(shù)據(jù)在聚集索引中的組織關(guān)系,因此每張表可以有多個(gè)輔助索引,當(dāng)通過輔助索引來查找數(shù)據(jù)時(shí)候,InnoDB存儲(chǔ)引擎會(huì)遍歷輔助索引并通過葉子節(jié)點(diǎn)上的指針獲得指向主鍵索引的主鍵,讓后通過主鍵索引再來找一次最終找到一個(gè)完整的記錄。

  • 案例

    • 如果在一顆高度為3(根算0 層)的輔助索引中查找數(shù)據(jù),那么需要對(duì)這可輔助索引遍歷3次找到指定主鍵
    • 如果聚集索引樹的的高度同樣是3,那么還需要對(duì)聚集索引在進(jìn)行三次查找,才能最終找到一個(gè)完整的行數(shù)據(jù)所在的頁(yè)(InnoDB最小存儲(chǔ)單元是頁(yè))
    • 因此一共需要6次邏輯IO來訪問最終的一個(gè)數(shù)據(jù)頁(yè)。
  • 此處也行會(huì)有疑問,為啥不直接將負(fù)責(zé)索引葉子上的 書簽指針之間指向行數(shù)據(jù)所在的頁(yè)呢,這樣就可以和聚集索引一樣,通過遍歷一個(gè)B+樹的索引就可以找到我們需要的數(shù)據(jù)頁(yè)所在的位置,少了一次IO操作。

    • 的確在某些情況,例如只讀的時(shí)候,書簽是行標(biāo)識(shí)的方式的非聚集索引 比 書簽是主鍵方式的非聚集索引要快。
    • 但是這是考慮在OLTP(Online Transaction Processing, 在線事務(wù)處理)應(yīng)用的情況下,表可能還需要提供其他服務(wù),例如,insert,update,delete等DML操作。當(dāng)進(jìn)行這種操作時(shí)候,書簽為行的標(biāo)識(shí)符方式的非聚集索引可能就需要不斷的更新行標(biāo)識(shí)符所指向的數(shù)據(jù)頁(yè)面的位置,這時(shí)候的開銷可能就大于書簽為主鍵的非聚集索引了
  • 又有另外一個(gè)疑問,那么DML操作也會(huì)影響主鍵索引,這個(gè)效率也會(huì)降低嗎:

    • DML操作的確會(huì)影響,但是主鍵是不能修改的,對(duì)于聚集索引來說 DML操作只會(huì)存在增加節(jié)點(diǎn)或者刪除節(jié)點(diǎn)的情況,不會(huì)變更行的地址,而只是修改節(jié)點(diǎn)的指針數(shù)據(jù)而已
    • B+樹的節(jié)點(diǎn)操作我們?cè)谥罢鹿?jié) 數(shù)據(jù)結(jié)構(gòu)與算法–B樹原理及實(shí)現(xiàn) 中有過詳細(xì)的解釋。

B+樹索引的管理

  • 索引的創(chuàng)建和刪除通過兩種方法,一種ALTER TABLE,一種CREATE/DROP index,具體預(yù)發(fā)略
  • 索引可以索引整個(gè)列的數(shù)據(jù),也可以索引一個(gè)列的開頭N行數(shù)據(jù),例如建立前100 行的索引如下:
alter TABLE t add key idx_b(b(100));
  • MySQL數(shù)據(jù)庫(kù)存在一個(gè)普遍問題,所有對(duì)所有的添加,刪除操作,MySQL數(shù)據(jù)庫(kù)都是先創(chuàng)建一個(gè)新的臨時(shí)表,然后把數(shù)據(jù)導(dǎo)入臨時(shí)表,刪除原表,在吧臨時(shí)表重命名為原來的表,因此對(duì)于一張大表,添加,刪除索引非長(zhǎng)久時(shí)間,

  • InnoDB存儲(chǔ)引擎從InnoDB Plugin開始,支持一種稱為快速索引的創(chuàng)建方法,但是只限定于輔助索引,對(duì)于主鍵的創(chuàng)建和刪除還是需要重建一張表。對(duì)于輔助索引的創(chuàng)建,InnoDB存儲(chǔ)引擎會(huì)對(duì)表加上一個(gè)s鎖。創(chuàng)建過程,不需要重建表,因此速度快,但是創(chuàng)建過程中上了S鎖,因此創(chuàng)建過程中該表只進(jìn)行讀。

  • 刪除的話更簡(jiǎn)單,只需要InnoDB存儲(chǔ)引擎內(nèi)部視圖更新,將輔助索引空間標(biāo)記可用即可,并刪除MySQL內(nèi)部視圖上對(duì)改表索引定義。

  • 可用用如下方法查看索引:

show index from t

  • 上圖中,有3個(gè)索引,一個(gè)主鍵索引,b列的非聚集索引,a,b的復(fù)合索引,如下圖:

  • 具體每個(gè)列的含義:

    • Table:索引所在表名
    • Non_unique:非唯一索引,可以看到primaryKey是0,因?yàn)楸仨毷俏ㄒ凰饕?/li>
    • Key_name:索引名稱,我們可以通過這個(gè)名稱來DROP INDEX
    • Sql_in_index:索引中該列的位置,如看到聯(lián)合索引idx_a_b就比較直觀的標(biāo)識(shí)復(fù)合索引,位置有兩個(gè)1,2
    • Column_name:索引列
    • Collation:列以什么方式存儲(chǔ)在索引中。可以上‘A’或者NULL。B+樹總是A,即排序的。如果使用了Heap存儲(chǔ)引擎,并且建立了Heap索引,這里就會(huì)顯示NULL了,因?yàn)镠ash根據(jù)Hash桶來存放索引數(shù)據(jù),而不是對(duì)數(shù)據(jù)進(jìn)行排序
    • Cardinality:非常重要的值,表示索引中唯一值的數(shù)目的估計(jì)值。Cardinality表示的行數(shù)如果非常小,說明我們可能不需要這個(gè)索引,比如以上案例,只有四條數(shù)據(jù),完全沒有必要索引的。
    • Sub_part:是否是列的部分被索引。如果看idx_b這個(gè)索引,這里顯示100,表示我們只索引b列的前100個(gè)字符,如果索引整個(gè)列,該字段值是NULL
    • Packed:關(guān)鍵字如何被壓縮。如果沒有被壓縮,則為NULL
    • Null:是否索引的列含義NULL值,可以看到idx_b這里是yes,因?yàn)槲覀兌xb列的時(shí)候允許NULL
    • Index_type:索引類型。InnoDB存儲(chǔ)引擎只支持B+樹索引,所以這里顯示的都是BTREE
    • Comment:注釋
  • 其中Cardinality值比較關(guān)鍵,查詢優(yōu)化器 會(huì)根據(jù)這個(gè)值來判斷是否使用這個(gè)索引。但是這個(gè)值并不是實(shí)時(shí)更新,并非每次索引的更新都會(huì)更新改值,這樣代價(jià)太大。因此這個(gè)值是不太準(zhǔn)確的,只是一個(gè)估計(jì)值。上面顯示的Cardinality為2,但是顯然表中有四條數(shù)據(jù),這個(gè)應(yīng)該是4的。如果需要更新Cardinality信息,可以使用命令如下:

ANALYZE table t
  • 不過這條命令在每個(gè)系統(tǒng)上可能得到的結(jié)果不一樣,因?yàn)锳nalyzeTable 現(xiàn)在還存在問題,可能會(huì)影響得到最后的結(jié)果,另一個(gè)問題是MySql對(duì)Cardinality計(jì)數(shù)的問題
  • 某些情況下可能會(huì)發(fā)生即使你建立了索引,但是查詢這個(gè)字段確沒有用到,或者,explain兩條基本一樣的語(yǔ)句,但是最終出來的結(jié)果一個(gè)用索引,一個(gè)不用索引,這個(gè)都和查詢優(yōu)化器對(duì)Cardinality的數(shù)量判斷做的優(yōu)化有關(guān)系。

上一篇:數(shù)據(jù)結(jié)構(gòu)與索引-- mysql InnoDB存儲(chǔ)引擎索引
下一篇:數(shù)據(jù)結(jié)構(gòu)與索引-- mySql索引詭異事件

總結(jié)

以上是生活随笔為你收集整理的数据结构与索引-- B+树索引的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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