關注"資料與人",聚焦技術與人文,分享乾貨,共同成長!
索引是一種提高我們查詢效率的資料結構,大家肯定很熟悉,在日常資料庫優化工作中經常會接觸到。
今天說一說索引的底層結構。
mysql 索引一般是雜湊表或 b+ 樹,常用的 innodb 引擎預設使用的是 b+ 樹來作為索引的資料結構。
為什麼不用雜湊表?
雜湊表(也叫雜湊表),是根據關鍵碼值(key value)而直接進行訪問的資料結構。它通過把關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。
簡單地說,雜湊索引就是採用一定的雜湊演算法,把鍵值換算成新的雜湊值,檢索時不需要類似b+樹那樣從根節點到葉子節點逐級查詢,只需一次雜湊演算法即可立刻定位到相應的位置,速度非常快。
這裡的對應關係f稱為雜湊函式,又稱為雜湊(hash函式),採用雜湊技術將記錄儲存在一塊連續的儲存空間中,這塊連續儲存空間稱為雜湊表或雜湊表(hash table)。
因為索引自身只需儲存對應的雜湊值,所以索引的結構十分緊湊,這也讓雜湊索引查詢的速度非常快。然而,雜湊索引也有他的限制:
因為這些限制,雜湊索引只適用於某些特定的場合。如果使用 b+ 樹作為索引資料結構,那麼訪問或修改一條資料的時間複雜度是 o(log n),但是使用雜湊表作為索引結構幹這些活的時候,時間複雜度 o(1)。如果只是查一條資料或者修改一條資料,用雜湊表做索引肯定給力!但是一般業務系統不會這麼簡單。在我們業務開發中,不可能只操作一行資料。綜合考慮,還是 b+ 樹更適合作為索引的資料結構。在業務開發中,經常會遇到範圍查詢、排序查詢等需求。這個時候雜湊表索引就沒辦法高效的處理這些需求了。它只能通過掃表來實現這些功能,掃表是資料庫的噩夢。mysql 使用 b+ 樹資料結構非葉子節點只儲存鍵值,葉子節點會儲存資料或者是主鍵。並且在葉子節點中鍵是按照順序儲存的,使得範圍查詢、排序查詢等變得異常簡單。
為什麼不用 b 樹?
什麼是b樹?又叫做b- 樹(其實b-是由b-tree翻譯過來,所以b-樹和b樹是乙個概念) ,它就是一種平衡多路查詢樹。下圖就是乙個典型的b樹:
下面是對b樹的乙個詳細定義:
b+ 樹的非葉子節點上只儲存鍵值,而 b 樹的非葉子節點上不僅儲存鍵值還儲存資料。在 mysql 資料庫中資料頁的大小是固定的,innodb 引擎資料頁預設大小為 16 kb。b+ 樹這種做法是為了讓樹的階數更大,讓樹更矮胖。進行查詢的時候,磁碟 io 次數就會減少,查詢效率也會更快。b+ 樹的所有資料均儲存在葉子節點中,並且是按鍵值有序排列。但是 b 樹的資料分散在各個節點。進行範圍查詢,排序查詢的時候,b 樹的效率肯定不如 b+ 樹。
b樹和b+樹的區別:
為什麼是b+樹b+樹是b樹的變種,是基於b樹來改進的。為什麼b+樹會比b樹更加優秀呢?
b樹:有序陣列+平衡多叉樹;
b+樹:有序陣列鍊錶+平衡多叉樹;b+樹的關鍵字全部存放在葉子節點中,非葉子節點用來做索引,而葉子節點中有乙個指標指向一下個葉子節點。做這個優化的目的是為了提高區間訪問的效能。而正是這個特性決定了b+樹更適合用來儲存外部資料。
b+ 樹查詢過程
磁碟塊 1 中儲存 17 和 35 資料項,還有 p1、p2、p3 指標,p1 表示資料項小於 17 的磁碟塊,p2 表示資料項在 17 和 35 之間的資料項,p3 表示資料項大於 35 的資料項。非葉子節點不儲存資料,只儲存指引搜尋方向的資料項。我們知道每次 io 讀取乙個資料頁的大小,也就是乙個磁碟塊。假設我們要查詢 29 這個資料項,首先進行第一次 io 將磁碟塊 1 讀進記憶體,發現17 < 29 < 35,然後選用 p2 指標進行第二次 io 將磁碟塊 3 讀進記憶體,發現26 < 29 < 30,然後選用 p2 指標將磁碟塊 8 讀進記憶體,在記憶體中做二分查詢,找到 29,結束查詢。通過分析查詢過程,我們可以知道 io 次數和 b+ 樹的高度成正比。h 為樹的高度,m 為每個磁碟塊的資料項個數,n 為資料項總數。
從下面的公式可以看出如果資料量n一定,m越大相應的h越小。
b+ 樹一般能儲存多少資料?
這裡我們先假設 b+ 樹高為 2,即存在乙個根節點和若干個葉子節點,假設一行記錄的資料大小為 1 kb,那麼單個葉子節點(頁)中的記錄數等於 16 kb / 1 kb = 16 條資料。然後要計算出非葉子節點能存放多少指標,我們假設主鍵 id 為 bigint 型別,長度為 8 位元組,而指標大小在 innodb 原始碼中設定為 6 位元組,這樣一共 14 位元組,我們乙個頁中能存放多少這樣的單元,其實就代表有多少指標,即 16 kb / 14 b = 1170。那麼可以算出一棵高度為 2 的 b+ 樹,大概就能存放下 1170 * 16 = 18720 條資料。根據同樣的原理我們可以算出乙個高度為 3 的 b+ 樹就可以存放下 21902400 條資料。所以在 innodb 中 b+ 樹高度一般為 1 - 3 層,它就能滿足千萬級的資料儲存。在查詢資料時一次頁的查詢代表一次 io,所以通過主鍵索引查詢通常只需要 1 - 3 次邏輯 io 操作即可查詢到資料。
【後記】
其實資料庫索引調優是一項技術活,不能僅僅靠理論,因為實際情況千變萬化,而且mysql本身存在很複雜的機制,如查詢優化策略和各種引擎的實現差異等都會使情況變得更加複雜。但同時這些理論是索引調優的基礎,只有在明白理論的基礎上,才能對調優策略進行合理推斷並了解其背後的機制,然後結合實踐中不斷的實驗和摸索,從而真正達到高效使用mysql索引的目的。另外,mysql索引及其優化涵蓋範圍非常廣,本文只是涉及到其中一部分。如果有機會,希望再對本文未涉及的部分進行補充吧。
聚焦技術與人文,分享乾貨,共同成長!
MySQL 為什麼使用B 樹做索引結構
官方 索引是幫助mysql高效獲取資料的排好序的資料結構 mysql底層索引用的並不是完全的b樹,而是在b樹上做了一些改進得到的變種,也就是b 樹。非葉子節點不儲存data,只儲存索引 冗餘 可以放置更多的索引 葉子節點包含所有索引字段 葉子節點用雙向指標連線,提高區間訪問的效能 橫向可以儲存更多的...
為什麼mysql innodb索引是B 樹資料結構
一 為什麼mysql innodb索引是b 樹資料結構?言簡意賅,就是因為 1.檔案很大,不可能全部儲存在記憶體中,故要儲存到磁碟上 2.索引的結構組織要儘量減少查詢過程中磁碟i o的訪問次數 為什麼使用b tree,還跟磁碟訪問原理有關。3 b 樹所有的data域在葉子節點,一般來說都會進行乙個優...
mysql 為什麼使用b 樹作為索引的結構
mysql 為什麼使用b 樹作為索引的結構 一 b樹的特性 1.關鍵字分布再整棵樹的所有節點 2.任何乙個關鍵字出現且只出現在乙個節點中。3.搜尋有可能在非葉子節點結束.4.其搜尋效能等價於再關鍵字全集內做一次二分查詢 二 b 樹的特性 b 樹是b樹的一種變形樹 可以解決某些問題 1.所有關鍵字都出...