mysql索引初識
文章是學習了林曉斌老師在極客時間的《mysql實戰45講》後,根據自己的理解整理而成的。
什麼是索引?
當我們使用漢語字典查詢某個字時,我們會先通過拼音目錄查到那個字所在的頁碼,然後直接翻到字典的那一頁,找到我們要查的字,通過拼音目錄查詢比我們拿起字典從頭一頁一頁翻找要快的多,資料庫索引也一樣,索引就像書的目錄,通過索引能極大提高資料查詢的效率。
索引的實現方式
在資料庫中,常見的索引實現方式有雜湊表、有序陣列、搜尋樹
-
雜湊表
雜湊表是通過鍵值對(key-value)儲存資料的索引實現方式,可以將雜湊表想象成是一個數組,將索引通過雜湊函式計算得到該行資料在陣列中的位置,然後將資料存到陣列中,容易發現一個問題,如果兩個索引通過雜湊函式計算後得到的陣列位置相同要怎麼辦?在這裡,陣列的每個value都是一個連結串列,連結串列上的每個元素都是一個數據,新資料直接新增到連結串列尾部。
雜湊表.png
要注意的是,連結串列上的資料元素不是有序的,每次有新資料加入時,新資料時直接新增到連結串列尾部,這樣做的好處是新增資料時很方便。
雜湊表不擅長進行區間查詢,一般都用於等值查詢
1、兩個相鄰索引通過hash函式後計算得到的陣列位置不一定還保持相鄰
2、連結串列上的資料是無序的 -
有序陣列
顧名思義,有序陣列是按索引大小將資料儲存在一個數組上,因為該陣列是有序的,可以通過二分法很容易查到位置,找到第一個位置後,通過向左/向右遍歷很容易得到所求區間的資料。因此,無論是等值查詢還是區間查詢,效率都極高。
但缺陷也是顯而易見的,當向陣列中間n位置插入一條資料時,需將n後面的資料全部往後移動,所以,這種索引一般用於靜態儲存引擎。
-
搜尋樹
二叉搜尋樹:一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 二叉搜尋樹的左、右子樹也分別為二叉搜尋樹。
平衡二叉樹:平衡二叉樹是在二叉搜尋樹的基礎上引入的,指的是結點的左子樹和右子樹的深度差不超過1.
多叉樹:每個結點可以有多個子結點,子節點的大小從左到右依次遞增。
當使用平衡二叉實現索引時,結構如下圖

圖片來自課程文章
從圖中可發現,每次查詢最多需要訪問4個節點必能得到所要資料。例如查詢user2時,查詢過程為:userA-->userC-->userF-->user2。
所以查詢速度很高,同時,因為搜尋樹的特性(左子樹小於右子樹),區間查詢也很方便。
如果搜尋樹存於記憶體中,與多叉樹相比,二叉樹的搜尋速率是最高的,但實際上資料庫使用的是n叉樹而不是二叉樹。
1、索引不僅存於記憶體,還是寫到磁碟上
2、搜尋樹上的每個結點在磁碟上表現為一個數據塊
3、多叉樹每個結點下可以有多個子節點,所以儲存相同資料量時多叉樹的樹高比二叉樹小,查詢一個數據需要訪問的結點數更少,即查詢過程訪問更少的資料塊。查詢速度較高。
innodb的索引模型
innodb使用B+樹作為索引結構。
在B+樹中,我們將節點分為葉子結點和非葉子結點,非葉子結點上儲存的是索引,而且一個節點可以儲存多個索引;資料全部存於葉子結點上,根據葉子結點的內容不同,innodb索引分為主鍵索引和非主鍵索引。非主鍵索引也稱為二級索引。
主鍵索引的葉子結點中儲存的資料為整行資料,而非主鍵索引葉子節點儲存的是主鍵的值。

主鍵索引圖

非主鍵索引圖
通過主鍵索引查詢資料時,我們只需查詢主鍵索引樹便可以獲取資料;通過非主鍵索引查詢資料時,我們先通過非主鍵索引樹查詢到主鍵值,然後再在主鍵索引樹搜尋一次,這個過程稱為回表,也就是說非主鍵索引查詢會比主鍵查詢多搜尋一棵樹。所以我們應儘可能使用主鍵查詢。
索引維護
新增新行時,將會在索引表上新增一條記錄,如果是索引遞增插入時,資料都是追加在當前最大索引之後,不會對樹中其他資料造成影響;如果新加入的資料的索引值位於節點的中間,需要挪動部分節點的位置,從而保持索引樹的有序性。
而且,相鄰多個節點是儲存在同一個資料頁上的,此時,如果是在已經儲存滿狀態的資料頁中插入節點,會申請新的資料頁,將部分資料挪動到新的資料頁,這個過程稱為頁分裂,頁分裂除了會影響效能,還會降低磁碟空間利用率。不規則資料插入時,會造成頻繁的頁分裂。
當相鄰兩個頁由於刪除了資料,利用率很低之後,會將資料頁做合併
所以,一般情況下會採用遞增主鍵,使新資料遞增插入。
使用業務邏輯欄位做主鍵有什麼優缺點?
1、業務邏輯欄位不容易保證索引樹結點有序插入,這樣寫入成本較高。
2、innodb預設使用整數型別作為主鍵,主鍵長度較小,二級索引的葉子結點中儲存的是主鍵值,主鍵長度越小,二級索引的葉子結點佔用空間也就越小。
3、當然,使用業務邏輯欄位做主鍵也有好處,可以避免回表,每次只需掃描一次主鍵索引樹即可
綜上,從效能和儲存空間方面考量,自增主鍵往往是更合理的選擇,當業務場景有且只有一個索引,而且該索引為唯一索引時,此時更適合使用業務邏輯欄位作為主鍵。
因為資料修改/刪除、頁分裂等原因,會導致資料頁空間利用率降低,此時,可以考慮重建索引,將資料按順序插入,提高磁碟空間利用率。但重建主鍵索引和普通索引會有不同影響,重建普通索引,可以達到提高空間利用率的目的,且不會對其他索引造成影響,但如果重建主鍵索引就不合理了,會影響所有普通索引,效能影響較大,而且無論是新建/刪除主鍵,都會重建整張表。這時我們可以使用alter table T engine=InnoDB這個語句代替。
檢視索引利用率
檢視performance_schema.table_io_waits_summary_by_index_usage表