1. 程式人生 > 其它 >mysql 索引學習

mysql 索引學習

1.索引功能

轉自:https://blog.csdn.net/qq_39871711/article/details/105356927

索引的作用是做資料的快速檢索,而快速檢索的實現的本質是資料結構。通過不同資料結構的選擇,實現各種資料快速檢索。

比如上面這個資料表,如果 Mysql 沒有實現索引演算法,那麼查詢 id=7 這個資料,那麼只能採取暴力順序遍歷查詢,找到 id=7 這個資料需要比較 7 次,如果這個表儲存的是 1000W 個數據,查詢 id=1000W 這個資料那就要比較 1000W 次,這種速度是不能接受的。

2.索引實現的資料結構

2.1 雜湊演算法

雜湊演算法:也叫雜湊演算法,就是把任意值(key)通過雜湊函式

變換為固定長度的 key 地址,通過這個地址獲取資料。

雜湊索引的過程:

select  *  from user where id=7;
  • 雜湊演算法首先計算儲存 id=7 的資料的實體地址 addr=hash(7)=4231,
  • 而 4231 對映的實體地址是 0x77,0x77 就是 id=7 儲存的額資料的實體地址,
  • 通過該獨立地址可以找到對應 user_name='g'這個資料。

但是雜湊無法實現範圍查詢

select * from user where id >3;

2.2 BST二叉查詢樹

普通的二叉查詢樹有個致命缺點:極端情況下會退化為線性連結串列,二分查詢也會退化為遍歷查詢,時間複雜退化為 O(N),檢索效能急劇下降。

2.3AVL 樹和紅黑樹

兩者都會自動旋轉保持平衡,紅黑樹在順序插入時會存在右傾的趨勢

AVL,AVL 樹是個絕對平衡的二叉樹,因此他在調整二叉樹的形態上消耗的效能會更多。

AVL 樹順序插入 1~16 個節點,查詢 id=16 需要比較的節點數為 4。從查詢效率而言,AVL 樹查詢的速度要高於紅黑樹的查詢效率(AVL 樹是 4 次比較,紅黑樹是 6 次比較)。從樹的形態看來,AVL 樹不存在紅黑樹的“右傾”問題。也就是說,大量的順序插入不會導致查詢效能的降低,這從根本上解決了紅黑樹的問題。

總結一下 AVL 樹的優點:

  1. 不錯的查詢效能(O(logn)),不存在極端的低效查詢的情況。

  2. 可以實現範圍查詢、資料排序

資料庫查詢資料的瓶頸在於磁碟 IO,如果使用的是 AVL 樹,我們每一個樹節點只儲存了一個數據,我們一次磁碟 IO 只能取出來一個節點上的資料載入到記憶體裡,那比如查詢 id=16 這個資料我們就要進行磁碟 IO 四次,這是多麼消耗時間的。所以我們設計資料庫索引時需要首先考慮怎麼儘可能減少磁碟 IO 的次數。【二叉樹中的節點不是連續儲存的,是離散的】

磁碟 IO 有個有個特點,就是從磁碟讀取 1B 資料和 1KB 資料所消耗的時間是基本一樣的,我們就可以根據這個思路,我們可以在一個樹節點上儘可能多地儲存資料,一次磁碟 IO 就多載入點資料到記憶體,這就是 B 樹,B+樹的的設計原理了。

2.4 B樹

每個節點可以儲存多個key。

總結來說,B 樹用作資料庫索引有以下優點:

  1. 優秀檢索速度,時間複雜度:B 樹的查詢效能等於 O(h*logn),其中 h 為樹高,n 為每個節點關鍵詞的個數;

  2. 儘可能少的磁碟 IO,加快了檢索速度;

  3. 可以支援範圍查詢

2.5.B+樹

B 樹和 B+樹有什麼不同呢?

第一,B 樹一個節點裡存的是資料,而 B+樹儲存的是索引(地址),所以 B 樹裡一個節點存不了很多個數據,但是 B+樹一個節點能存很多索引B+樹葉子節點存所有的資料

第二,B+樹的葉子節點是資料階段用了一個連結串列串聯起來,便於範圍查詢。【便於順序查詢吧?】

過 B 樹和 B+樹的對比我們看出,B+樹節點儲存的是索引,在單個節點儲存容量有限的情況下,單節點也能儲存大量索引,使得整個 B+樹高度降低,減少了磁碟 IO。

其次,B+樹的葉子節點是真正資料儲存的地方,葉子節點用了連結串列連線起來,這個連結串列本身就是有序的,在資料範圍查詢時,更具備效率。

因此 Mysql 的索引用的就是 B+樹,B+樹在查詢效率、範圍查詢中都有著非常不錯的效能。

2.5.1 B+樹從磁碟讀取

轉自:https://www.cnblogs.com/luckgood/p/8979088.html

大多數人可能認為肯定還是B+樹快,畢竟儲存同樣多的資料,100階的B+樹肯定比平衡二叉樹的高度要低的多。但是別忘了B樹在一個結點可能需要比較很多次才能找到下一層的結點,但是平衡二叉樹只要比較一次就可以向下走一層。所以綜合起來,其實兩者索引的速度幾乎(甚至說就是)是一樣的

那麼我們為什麼還要使用B+樹呢?這是因為上面說索引速度相當的前提是兩者的資料結構都位於記憶體中,當我們要在磁碟上索引一個記錄時,將磁碟中的資料傳輸到記憶體中才是花費時間的大頭,而在記憶體中的索引過程所花的時間基本是可以忽略不計的。【磁碟IO是主要的限制】

主存和磁碟之間的資料交換不是以位元組為單位的,而是以n個扇區為單位的(一個扇區有512位元組),通常是4KB(8個扇區),8KB(16個扇區),16KB,……64KB為單位的。假設,我們現在選擇4KB作為記憶體和磁碟之間的傳輸單位,那麼我們在設計B+樹的時候,不論是索引結點還是葉子結點都使用4KB作為結點的大小

我們這時不妨再假設一個記錄的大小是1KB,那麼一個葉子結點可以存4個記錄。而對於索引結點(大小也是4KB),由於只需要存key值和相應的指針,所以一個索引結點可能可以儲存100~150個分支,我們不妨就取100吧。當然這和上面第2節和第三節中的情況不太一樣,因為現在索引結點的階數是100,而葉子結點的階數是4,兩者並不一致,但這並沒有什麼問題。

我們考慮如上圖所示的B+樹,下面的B+樹有三層,兩層是索引結點,最後一層是葉子結點。那麼這個三層的B+樹最多可以存400萬個記錄。

100*100*100*4=400w?

如果這個B+樹儲存到硬碟中,我們怎麼根據記錄的key找到對應的記錄呢?

  1. 首先我們要讀取這個B+樹的根結點到記憶體(花費一個IO的時間)然後在記憶體中進行索引,然後根據key找到對應的分支;
  2. 將這個分支所指向的第二層索引結點讀取到記憶體中(花費第二個IO時間)然後在記憶體中進行索引;
  3. 根據key找到對應的分支,而這個分支指向的就是葉子結點,我們最後將這個葉子結點讀取到記憶體中(花費的第三個IO時間)判斷是否存在這個記錄。

綜上,只需3次IO。快速的原因是,索引結點中不存資料,只存鍵和指標,所以一個索引結點就可以儲存大量的分支,而一個索引結點只需要一次IO即可讀取到記憶體中

當記錄的大小可變時,葉子結點中記錄該如何儲存?

  • 檔案系統及資料庫中的B+樹是不考慮階數這一個概念的,結點(即包括葉子結點,也包括索引結點)中僅遵行一個規則,如果剩餘空間夠大那麼就存入資料,如果剩餘空間不夠,只能分裂後再存入。當B+樹儲存在磁碟中的情況時,IO效率才是第一要考慮的因素。CPU在某個結點內部多比較幾次或少比較幾次和IO花費的時間相比就不值得一提了。
  • 如果某條記錄太大,即使葉子結點中還剩餘一多半的空間但仍然存不下怎麼辦?這個時候MySql稱之為行溢位,簡單的解決方式就是把記錄儲存在溢位頁(磁碟的其它空閒地方)中,然後葉子結點中儲存的是這個記錄的指標。