深入理解MySQL索引 上

2021-10-05 16:52:50 字數 3248 閱讀 2507

簡單來說,索引的出現就是為了提高資料查詢的效率,就像字典的目錄一樣。如果你想快速找乙個不認識的字,在不借助目錄的情況下,那我估計你的找好長時間。索引其實就相當於目錄。

索引的出現是為了提高查詢效率,但是實現索引的而方式有很多種,所以這裡也就引入了索引模型的概念。可以用於提高查詢效率的資料結構有好多種,這裡先介紹常見的三種。分別是雜湊表、有序陣列、搜尋樹

雜湊表是一種以鍵值對形式儲存的資料結構,我們只需要輸入待查詢的值即key,就可以找到相對應的值value。雜湊表思路很簡單,把值放在陣列中,用雜湊函式把key換算成乙個數字,確定在陣列中的位置,再將value放入這個位置。

但是不可避免的,會出現雜湊衝突現象。不同的key傳入雜湊函式計算出的結果是同乙個。處理這種情況的一種方法是,在衝突的位置上建立乙個鍊錶。

圖中user2和user4根據身份證號算出的值都是n,但沒關係,後面還跟了乙個鍊錶。假設,這時候你需要查id_card_n2對應的名字是什麼,處理步驟是:首先,將id_card_n2通過雜湊函式算出n;然後順序遍歷鍊錶找到user2。

需要注意的是,圖中的四個id_card_n的值並不是遞增的,這樣做的好處是增加新的user是速度很快,但是缺點是,因為不是有序的對於區間查詢的速度是很慢的,需要乙個乙個遍歷完。

所以,雜湊表這種結構適用於只有等值查詢的場景,比如memcached以及一些nosql引擎。

有序陣列在等值查詢和範圍查詢場景中的效能都是十分優秀的還是和上面的身份證查詢的例子一樣,如果用有序陣列來實現,會是這個樣子。

這裡我們假設身份證號不重複,這個陣列就是按照身份證號遞增的順序儲存的。這時候要是查詢id_card_n2對應的名字,用二分法就可以快速得到,時間複雜度為o(logn)。

同時有序陣列這種結構支援範圍查詢。你要查身份證號在[x,y] 區間的user,可以先用二分查詢找到x,如果找不到x就找x的前乙個user,依次向後遍歷,直到找到第乙個大於y的身份證號,退出迴圈。

如果只關注查詢效率,有序陣列是最好的資料結構了。但是在需要更新資料的時候就麻煩了,你往中間插入乙個記錄必須挪動後面的所有記錄,成本太高。

所以,有序陣列只適用於靜態儲存,比如你要儲存的是2023年某個城市的所有人口資訊,這類不會在修改的資料。

如果上面的例子採用二叉搜尋樹來實現的話。

二叉搜尋樹的特點是:左孩子小於父節點,父節點小於右孩子。這樣如果你要查id_card_n2的話。按照圖中的搜尋順序是usera->userc->userf->user2。時間複雜度是o(logn)。

當然為了維持o(logn)的查詢複雜度,你需要保持這棵樹是平衡二叉樹。這樣做更新的時間複雜度也是o(logn)。

二叉樹是搜尋效率最高的,但是實際上大多數資料庫儲存引擎並不使用二叉樹,原因是索引布置存在記憶體中還存在硬碟上。

如果乙個二叉樹的樹高是20,依次查詢可能需要訪問20個資料塊,對磁碟操作需要多次io,這樣效率低下。為了讓查詢盡量的少讀磁碟,就必須讓查詢過程訪問盡量少的資料塊。那麼我們不應該使用二叉樹,應該換成n叉樹。n的大小取決於資料塊的大小。

n叉樹,由於在讀寫上的效能優點,以及適配磁碟的訪問模式,已經被廣泛應用在資料庫引擎中。

mysql的索引是在儲存引擎層實現的,所以並沒有統一的索引標準,即不同的儲存引擎的索引工作方式也不一樣,而即使多個儲存引擎支援同一種型別的索引,那他們的底層實現也可能不同。現在來說說innodb的索引模型。

在innodb中,表都會根據主鍵順序以索引的形式存放的,這種儲存方式的表稱為索引組織表。又因為前面我們提到的,innodb使用了b+樹索引,所以資料都是儲存在b+樹中的。

每乙個索引在innodb裡面對應的一棵b+樹。

例如現在有兩個索引,乙個是主鍵索引id,另乙個是非主鍵索引又稱為非聚簇索引 k。

從圖中不難看出,根據葉子結點的內容,索引型別分為主鍵索引和非主鍵索引。

主鍵索引的葉子結點存的是整行資料,**在innodb裡面,主鍵索引也被稱為聚簇索引。非主鍵索引也被稱為非聚簇索引。**非聚簇索引的葉子結點內容是主鍵的值。在innodb裡面,非主鍵索引也被稱為二級索引

基於主鍵索引和普通索引的查詢有什麼區別?

也就是說,基於非主鍵索引的查詢需要多掃瞄一棵索引樹。因此,我們在應用中應該盡量使用主鍵查詢。

b+樹為了維護索引你的有序性,在插入新的值時需要做必要的維護。以上圖為例,如果插入行的一行的id值是700,者只需要在r5後面新增乙個值700.如果新插入的id是400,那就麻煩了,需要邏輯上挪動後面的資料,空出位置。

更糟糕的情況是,如果r5所在的資料頁已經滿了,根據b+樹的演算法,這時候需要申請乙個新的資料頁,然後挪動剩餘部分,這個過程叫做頁**。這種情況下,效能自然會受到影響。

頁**除了影響效率還影響著頁的利用率。原本放在乙個頁的資料,現在分到兩個頁上,利用率降低了50%。

當相鄰的兩個頁刪除了資料,利用率很低後,會將資料頁進行合併。合併過程就是葉**的逆向過程。

自增主鍵什麼時候用

建表時定義自增主鍵:

not

null

primary

keyauto_increment

定義完成後,在插入資料的時候可以不用指定id的值,系統會獲取當前id最大值+1作為下乙個記錄的id值。

也就是說,自增主鍵的插入資料模式,符合前面提到的遞增插入的場景。每次插入一條新紀錄,都是追加操作,不涉及其他挪動操作,也不會觸發頁**。

再從儲存空間上思考,假設你的表中有唯一乙個字段,比如字串型別的身份證號,那應該使用身份證號碼作為主鍵還是使用自增主鍵。

由於每個非主鍵索引的葉子結點都包含主鍵的值,如果用整形作為主鍵需要4位元組,如果是長整形需要8位元組,如果是身份證號需要20個位元組。

**顯然,主鍵長度越小,不同索引的葉子結點就越小,普通索引占用的空間也就越小。

**適合業務字段作為主鍵的場景

只有乙個索引

該索引必須是唯一索引

平時建立索引,如果需要建立多個索引建議使用自增主鍵,如果是只有乙個索引並且是唯一索引那就是業務字段作為索引。

mysql 索引深入理解 深入理解MySql的索引

為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...

深入理解mysql索引

三 b tree 索引是幫助mysql高效獲取資料的排好序的資料結構。mysql中索引預設的資料結構為b tree。新建兩張表test innodb 儲存引擎為innodb test myisam 儲存引擎為myisam 當進入到mysql安裝目錄下的data資料夾可以看到test innodb.f...

深入理解mysql索引 深入了解mysql索引

1 索引原理 索引被用來快速找出在乙個列上用一特定值的行。沒有索引,mysql不得不首先以第一條記錄開始,然後讀完整個表直到它找出相關的行。表越大,花費時間越多。對於乙個有序字段,可以運用二分查詢 binary search 這就是為什麼效能能得到本質上的提高。myisam和innodb都是用b t...