【MySQL】Mysql索引優化與底層數據結構深入剖析 - 筆記

索引

使用索引,會提前存儲被索引字段對應行的磁盤文件地址指針,做一次IO就能查找到數據。
在這裏插入圖片描述

二叉樹

遞增的索引不適合用二叉樹來維護,因爲遞增的id會導致二叉樹退化成爲鏈表,這樣建立索引的效果和不建立索引的差別不大。因此MySQL不使用二叉樹做索引。

數據結構可視化網站
在這裏插入圖片描述

紅黑樹

單邊增長不平衡時,紅黑樹會自動平衡。
JDK1.8之後,HashMap使用的就是紅黑樹。
在某些場景下,紅黑樹也會存在問題:樹的高度會一直增長,數據量大的時候,還是會有很多次IO。
在這裏插入圖片描述

B樹

B樹是對紅黑樹的改造,讓一個節點能夠存儲更多的元素。
在這裏插入圖片描述
爲什麼不把所有元素都加載進一個節點,放進內存中?

  • 佔用內存過大;一次磁盤IO有大小限制,加載不過來,會很慢
  • 沒有必要把一個節點搞得太大。

使用show global status like'Innodb_page_size'查看MySQL默認設置一個葉節點(頁)的值:16Kb

B+樹

MySQL底層使用的是B+樹,是對B樹的改造。
把非葉子節點的data數據都挪到了葉子結點上去存儲,這樣,在16kb大小固定的情況下,一個葉子節點在橫向上能存放更多的索引。

例如,查找30這個元素對應的data的過程:
第一次,將15 56 77 load 進內存:
第二次,將15 20 49 load 進內存
第三次,將20 30 load 進內存,進而取出30對應的data

因此,如果添加了合適的索引,只需要進行2-3次磁盤IO,就可以找到數據。
如果不添加索引的話,需要一行一行去找,十分緩慢。
在這裏插入圖片描述

關於存儲引擎

存儲引擎是表級別的,不同的表可以有不同的存儲引擎

主鍵自帶主鍵索引。

MyISAM引擎的查詢過程:

  • 先去索引文件中查找指針
  • 再去指針的位置磁盤中把data查詢出來

數據和索引是分開存儲的,它的葉子結點只存儲了數據在磁盤對應文件的地址。

在這裏插入圖片描述
MySQL數據文件存儲在哪裏?都有哪些文件?如圖:
在這裏插入圖片描述

InnoDB引擎的查詢過程:

InnoDB的主鍵索引是聚集索引。(什麼是稀疏索引?稀疏索引就是非聚集索引)
.ibd文件同時存儲索引和數據,以B+樹的結構組織起來,在葉子節點包含了一條記錄(行)的所有數據。
在這裏插入圖片描述
在這裏插入圖片描述

常見問題

爲什麼InnoDB表必須有主鍵,並且推薦使用整型自增主鍵?

MySQL InnoDB引擎設計數據默認使用B+樹來組織。
如果沒設置主鍵,MySQL會自動找一個能夠作爲主鍵的字段,作爲索引去維護。
如果MySQL找不到合適的主鍵,MySQL會自己維護一個隱藏列,用這個隱藏列做索引。

爲什麼推薦使用自增的主鍵?
自增的主鍵有利於維護B+樹(每次都向尾部追加),而如果不自增的話,可能會插入到B+數中間位置的某個節點中,而每個節點的大小是有限制的。超出限制後,爲了保持樹的平衡,會造成葉節點分裂,導致插入性能下降。

用UUID作爲主鍵怎麼樣?

在B+數查找的過程需要進行多次比較大小。UUID是作爲字符串存儲的,而用整型數字較大小效率更高,並且整型的索引在存儲的時候佔用的磁盤空間更小。

用Hash作爲索引怎麼樣?

用Hash的話,select * from t where col1 > 6這樣的範圍查詢無法加快查詢速度
而如果使用B+樹,葉子結點的(雙向)指針提高了範圍查詢的速度。

分庫分表怎麼辦?是不是UUID更方便?

分庫分表也可以使用整型。
參考雪花算法:Twitter 開源的分佈式 id 生成算法。其核心思想就是:使用一個 64 bit 的 long 型的數字作爲全局唯一 id。在分佈式系統中的應用十分廣泛,且ID 引入了時間戳,基本上保持自增的。這 64 個 bit 中,其中 1 個 bit 是不用的,然後用其中的 41 bit 作爲毫秒數,用 10 bit 作爲工作機器 id,12 bit 作爲序列號。

聯合索引是什麼結構?

幾個字段一起存儲在節點彙總。排序方式:按照字段逐個進行排序,維護B+樹從左到右依次遞增。
使用聯合索引時,注意最左前綴原則:如果a b c三列加了索引,查找時如果根據a b查找,能走索引。如果根據b c查找,無法走索引。(不能跳過某一個索引,直接用後面的索引)
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章