mysql 字典索引_【大白话mysql】你真的了解 mysql 索引吗?
本文來源于公眾號: 跬步匠心
什么是索引?
當我們使用漢語字典查找某個字時,我們會先通過拼音目錄查到那個字所在的頁碼,然后直接翻到字典的那一頁,找到我們要查的字,通過拼音目錄查找比我們拿起字典從頭一頁一頁翻找要快的多,數據庫索引也一樣,索引就像書的目錄,通過索引能極大提高數據查詢的效率。
索引的實現方式
在數據庫中,常見的索引實現方式有哈希表、有序數組、搜索樹。
哈希表
哈希表是通過鍵值對(key-value)存儲數據的索引實現方式,可以將哈希表想象成是一個數組,將索引通過哈希函數計算得到該行數據在數組中的位置,然后將數據存到數組中,容易發現一個問題,如果兩個索引通過哈希函數計算后得到的數組位置相同要怎么辦?我們可以采用哈希鏈表,數組的每個 value 都是一個鏈表,新數據直接添加到鏈表尾部。
所以數據庫查詢過程為:索引通過哈希函數計算數據所在位置 --> 遍歷指定位置的鏈表,找到滿足條件的數據。
每次有新數據加入時,新數據時直接添加到鏈表尾部,所以添加數據時很方便。
哈希表不擅長進行區間查詢,一般都用于等值查詢,因為兩個相鄰索引通過 hash 函數后計算得到的數組位置不一定還保持相鄰,需要哈希多次才能把區間的數據全查出來。
有序數組
顧名思義,有序數組是按索引大小將數據保存在一個數組上,因為該數組是有序的,可以通過二分法很容易查到位置,找到第一個位置后,通過向左或者向右遍歷很容易得到所求區間的數據。因此,無論是等值查詢還是區間查詢,效率都極高。
但缺陷也是顯而易見的,當向數組中間 n 位置插入一條數據時,需將 n 后面的數據全部往后移動,所以,這種索引一般用于靜態存儲引擎。
搜索樹
二叉搜索樹:一棵空樹,或者是具有下列性質的二叉樹:若它的左子樹不空,則左子樹上所有結點的值均小于它的根結點的值;若它的右子樹不空,則右子樹上所有結點的值均大于它的根結點的值;二叉搜索樹的左、右子樹也分別為二叉搜索樹。
平衡二叉樹:平衡二叉樹是在二叉搜索樹的基礎上引入的,指的是結點的左子樹和右子樹的深度差不超過 1。
多叉樹:每個結點可以有多個子結點,子節點的大小從左到右依次遞增。
數據庫一般使用平衡樹來當索引的存儲數據結構,當使用平衡二叉實現索引時,結構如下圖。
從圖中可發現,每次查詢最多需要訪問 4 個節點必能得到所要數據。例如查詢 user2 時,查詢過程為:userA-->userC-->userF-->user2。所以查詢速度很高,復雜度為 O (log (n));平衡二叉樹的更新復雜度也為 O (log (n))。
區間查詢時,由于搜索樹的特性(左子樹小于右子樹),可以很快的排除掉不滿足條件的節點,查起來速度也是很快的。
思考下為什么用平衡搜索樹呢?
因為普通的二叉樹可能因為插入的數據最后變成一個很長的鏈表,查詢復雜度退化成 O (n)。
如果搜索樹存于內存中,與多叉樹相比,二叉樹的搜索速率是最高的,但實際上數據庫使用的是 n 叉樹而不是二叉樹。
索引不僅存于內存,還是寫到磁盤上,搜索樹上的每個結點在磁盤上表現為一個數據塊。
多叉樹每個結點下可以有多個子節點,所以存儲相同數據量時多叉樹的樹高比二叉樹小,查詢一個數據需要訪問的結點數更少,即查詢過程訪問更少的數據塊。查詢速度較高。
在 mysql 的 innodb 引擎中,使用 B + 樹來存儲數據,B + 樹是一種多叉平衡查找樹。
innodb 的索引模型
在 B + 樹中,我們將節點分為葉子結點和非葉子結點,非葉子結點上保存的是索引,而且一個節點可以保存多個索引;數據全部存于葉子結點上,并且葉子結點之間通過指針連接起來。
根據葉子結點的內容不同,innodb 索引分為主鍵索引和非主鍵索引。非主鍵索引也稱為二級索引。主鍵索引的葉子結點中保存的數據為整行數據,而非主鍵索引葉子節點保存的是主鍵的值。
通過主鍵索引查詢數據時,我們只需查找主鍵索引樹便可以獲取數據;通過非主鍵索引查詢數據時,我們先通過非主鍵索引樹查找到主鍵值,然后再在主鍵索引樹搜索一次,這個過程稱為回表,也就是說非主鍵索引查詢會比主鍵查詢多搜索一棵樹。所以我們應盡可能使用主鍵查詢。
B + 樹是一顆 N 叉樹,N 是由什么決定的?能否調整?
通過修改 page 的大小來間接調整 N 的大小。一個節點上的所有數據都在一個 page 中,頁越大,每頁存放的索引就越多,N 就越大。數據頁調整后,如果數據頁太小層數會太深,數據頁太大,加載到內存的時間和單個數據頁查詢時間會提高,需要達到平衡才行。
修改索引的大小。每個索引包括固定字節數的 Point 指針和索引字段內容,索引字段越小,每頁能存的索引就越多,N 就越大。
索引維護
添加新行時,將會在索引表上添加一條記錄,如果是索引遞增插入時,數據都是追加在當前最大索引之后,不會對樹中其他數據造成影響;如果新加入的數據的索引值位于節點的中間,需要挪動部分節點的位置,從而保持索引樹的有序性。
而且,相鄰多個節點是存儲在同一個數據頁上的,此時,如果是在已經存儲滿狀態的數據頁中插入節點,會申請新的數據頁,將部分數據挪動到新的數據頁,這個過程稱為頁分裂,頁分裂除了會影響性能,還會降低磁盤空間利用率。不規則數據插入時,會造成頻繁的頁分裂。所以,一般情況下會采用遞增主鍵,使新數據遞增插入。
當相鄰兩個頁由于刪除了數據,利用率很低之后,會將數據頁做合并。
什么情況下應該使用業務邏輯字段做主鍵?有什么優缺點?
業務邏輯字段不容易保證索引樹結點有序插入,這樣寫入成本較高。
innodb 默認使用整數類型作為主鍵,主鍵長度較小,二級索引的葉子結點中保存的是主鍵值,主鍵長度越小,二級索引的葉子結點占用空間也就越小。
當然,使用業務邏輯字段做主鍵也有好處,可以避免回表,每次只需掃描一次主鍵索引樹即可。
綜上,從性能和存儲空間方面考量,自增主鍵往往是更合理的選擇,但是當業務場景有且只有一個索引,而且該索引為唯一索引時,此時更適合使用業務邏輯字段作為主鍵,一個是避免回表,還有一個是只有一個索引也不需要考慮二級索引的空間占用情況了。
索引重建
因為數據修改、刪除、頁分裂等原因,會導致數據頁空間利用率降低,此時,可以考慮重建索引,將數據按順序插入,提高磁盤空間利用率。
重建普通索引時,直接先刪除索引,再重新創建即可。
alter table T drop index k;
alter table T add index(k);
復制代碼
主鍵索引不能通過上面的語句去重建,因為刪除主鍵索引后,innodb 會如下處理:
如果存在非空且字段類型為數值的唯一索引(INT and NOT NULL and UNIQUE INDEX), 會將第一個滿足條件的索引作為主鍵索引 , _rowid 為對應主鍵,值與唯一索引相同。(可通過 select _rowid from table 查詢)。
如果找不到合適的索引,那么 InnoDB 會自動生成一個不可見的名為 ROW_ID 的列名為 GEN_CLUST_INDEX 的主鍵索引,該列是一個 6 字節的自增數值,隨著插入而自增。
所以刪除主鍵索引的結果其實是修改了主鍵字段,而普通索引的葉子節點存的是主鍵的值,所以,一旦修改了主鍵字段,普通索引也會有影響,葉子節點的值將被修改成新的主鍵字段。
當主鍵索引需要重建時,更好的做法是直接使用 alter table t engine=innodb 重建表。
寫在最后
喜歡本文的朋友,歡迎關注公眾號「跬步匠心」,專注大白話分享實用技術
總結
以上是生活随笔為你收集整理的mysql 字典索引_【大白话mysql】你真的了解 mysql 索引吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android tv字体,best登陆「
- 下一篇: mysql.ini环境配置_MySQL配