mysql索引詳解-你的數據庫用對索引了嘛

mysql索引詳解-你的數據庫用對索引了嘛

mysql的索引一般分爲主鍵索引,唯一索引,普通索引,聯合索引,覆蓋索引等。

索引這麼多,到底該怎麼用,用哪個索引適合,需不需要索引呢?

innoDB的索引

innoDB裏面一般採用b+樹索引模型,當然還有其它比如哈希索引,全文索引,空間索引。但是常用的還是b+樹索引。

B+樹是一個N叉平衡樹。爲什麼不用二叉平衡樹呢,因爲二叉平衡樹高度太高了,n叉平衡樹可以控制樹的高度,大概在3-4的高度,而樹的根節點一般存在內存中,這樣只需要做2-3次磁盤操作就可以了。大量的減少了磁盤操作。

主鍵索引

主鍵索引是一種聚簇索引,什麼是聚簇索引呢,就是和數據放在一起的。b+樹的葉子節點存放的是頁,每個頁的默認大小是16kb。主鍵索引樹的葉子節點存放的是主鍵id和數據。一般我們都會用id做爲主鍵。如果一個表不指定主鍵,Innodb會使用row id作爲主鍵。

我們使用主鍵查詢數據,來看一下執行計劃。

explain select * from auth_users where id = 1;

在這裏插入圖片描述

可以看到裏面key列顯示的是primary,表示使用了主鍵索引。row列是1,表示掃描了一行。通過樹搜索的方式快速定位了主鍵id的位置並且取出數據進行了返回。

爲什麼主鍵推薦使用遞增id呢,這是因爲對索引樹的增刪改查要更加快速。所以一般使用自增主鍵。也避免了插入引起的頁分裂和刪除引起的頁合併

如果現在表裏有id=4,5,6的數據,你插入了一條id=3的數據。這時候存放id=4,5,6數據的數據頁滿了,就需要頁分裂,變成兩個數據頁。

頁合併就是相鄰的兩個數據頁的數據都挺少的,可以合併到一起,那麼就會頁合併。

使用自增主鍵則只需要不斷往後寫入就可以了,不需要擔心中間的插入。而且自增主鍵佔用的空間同樣相對較小。

二級索引

二級索引也是非聚簇索引。包括唯一索引普通索引。他們同樣是b+樹的方式存放,只是他們的葉子節點中存放的並不是真正的數據,而是主鍵id。那麼通過這種索引怎麼找到數據呢,其實是先找到對應的主鍵id,再去主鍵索引樹中通過主鍵id找到對應的數據,也叫回表

唯一索引和普通索引的區別在於查詢的時候,唯一索引查詢到條件對應的數據後不會接着查詢了,而普通索引會接着查詢,直到不滿足條件爲止。

覆蓋索引

覆蓋索引是一種優化的手段。覆蓋索引也是一種聯合索引

比如我們查詢用戶信息的時候,如果需要根據用戶名查詢用戶名和密碼。我們在用戶名字段創建了一個索引。那麼查詢的時候就會走索引,但是查到的是id,還需要再去主鍵中找到數據,取出用戶名和密碼兩個字段。

如果我們在用戶名的索引樹中不僅存了id,還存了我們需要的密碼字段,不就不需要再去回表了嗎?那我們就需要創建一個用戶名和密碼的聯合索引。這樣我們就不需要再回表了,這也就是覆蓋索引。覆蓋了我們要查詢的字段。當然,你通過索引查詢的時候,執行計劃顯示的行數還是1.這是因爲回表這個操作是在innoDB裏面做的,mysql是感覺不到的。

索引下推

索引下推也是一種優化。比如我們要查詢用戶名是張三密碼是123456的用戶。

select * from users where name = '張三' and pwd = '123456'

在mysql5.6以前,只能查詢到張三這個數據以後回表找到數據在判斷密碼。

而mysqll5.6增加索引下推的優化之後,可以在索引遍歷過程中,對name和pwd兩個字段同時做判斷。

唯一索引和普通索引

這兩個索引到底該怎麼選擇,比如用戶名字段,用戶名當然是不能重複的了。那麼它應該使用唯一索引還是普通索引呢?

一般用戶註冊的時候我們會判斷用戶名是否重複。所以用戶名字段加唯一索引的價值並不大,我們的業務已經能保證它不重複了。

我們在上面說過,查詢的時候,唯一索引查詢到數據直接就返回了,顯然要比普通索引快一些。

但是真的也就快了那麼一點,因爲InnoDB引擎在讀取的時候,是讀取一個數據頁的數據。它會先把一個數據頁讀取到內存中,然後查詢,那麼在內存中多查一次其實沒啥感覺。

在看一下更新的時候。

數據在內存裏面

如果數據在內存中,那麼唯一索引會判斷更新後是否會破壞唯一性,如果不破壞則更新。

普通索引則直接更新。

這裏顯示普通索引更好,不用判斷。但是這個影響頁很小,和上面一樣,在內存中操作的。

數據不在內存中

如果數據不在內存中,那麼唯一索引就需要從磁盤讀取數據,然後判斷,更新。

普通索引則直接寫入change buffer,然後就完成了,而change buffer則是在內存中,內存操作,少了磁盤操作。

整體來看,普通索引貌似比唯一索引更友好,唯一索引爲了唯一性犧牲了插入和修改的性能。

change buffer

這個是一塊內存中的空間,顧名思義,他就是爲了修改而生的,如果你修改了數據,不需要直接更新磁盤,而是放入change buffer.change buffer滿了,或者一定時間,或者當出現查詢操作的時候,會merge數據,比如你更新了手機號,然後要查詢這個用戶的手機號。那麼這時候內存中沒有這個數據,從磁盤查詢,磁盤查詢到的是以前的手機號,因爲數據沒有更新到磁盤。這時候change buffer就會把更新數據合併到內存中的數據,使得查詢到的是最新數據。

那麼爲什麼唯一索引不適用change buffer,因爲他需要判斷唯一性。

但是向剛纔舉得例子,更新完立即查詢,其實和唯一索引的更新沒有啥區別了,反而因爲change buffer還麻煩了。所以,change buffer更適合更新完不立即查詢的場景。

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