十三、mysql索引

轉載至鏈接:https://blog.csdn.net/alex_xfboy/article/details/82818753
提到數據庫索引,我想你並不陌生,在日常工作中會經常接觸到。比如某一個 SQL 查詢比較慢,分析完原因之後,你可能就會說“給某個字段加個索引吧”之類的解決方案。但到底什麼是索引,索引又是如何工作的呢?今天就讓我們一起來聊聊這個話題吧。
一句話簡單來說,索引的出現其實就是爲了提高數據查詢的效率,就像書的目錄一樣。一本 500 頁的書,如果你想快速找到其中的某一個知識點,在不借助目錄的情況下,那我估計你可得找一會兒。同樣,對於數據庫的表而言,索引其實就是它的“目錄”。
索引是幫助數據庫系統高效獲取數據的數據結構,索引可以幫助我們快速地定位到數據而不需要每次搜索的時候都遍歷數據庫中的每一行。其本質是一種數據結構,既然是一種數據結構自然要涉及到在物理介質上的存儲,以增加額外用於維護索引數據結構的存儲空間爲代價,換取數據庫中數據檢索效率的提升。

一、索引的數據結構

索引的出現是爲了提高查詢效率,可以用於提高讀寫效率的數據結構很多,常見的有哈希表、有序數組和二查樹、紅黑樹、B+樹等。
可以通過如下網站可視化各種樹的構造過程:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

1.1 哈希表

在這裏插入圖片描述
哈希表是一種以鍵 - 值(key-value)存儲數據的結構,我們只要輸入待查找的 key,就可以找到其對應的值即 Value。哈希的思路很簡單,把值放在數組裏,用一個哈希函數把 key 換算成一個確定的位置,然後把 value 放在數組的這個位置。
不可避免地,多個 key 值經過哈希函數的換算,會出現同一個值的情況。處理這種情況的一種方法是,拉出一個鏈表。
如上圖所示,我們將一系列的鍵值key通過哈希函數,得到hash碼,基於hash碼找到在桶上的位置,桶中每個元素存儲了value鏈的存儲地址。
hash表的搜索時間複雜度爲o(1),效率非常高,但是mysql底層並沒有使用哈希索引,這是因爲,相等性查詢(如id=4)時能很快檢索,但是不等性查詢(如id<4)等範圍方式查找,無法快速定位地址。

1.2 二叉樹

在這裏插入圖片描述
二叉樹的特點是:左中右 ,小中大;即左子節點小於父節點,父節點小於右子節點。
平衡二叉樹定義(AVL):它或者是一顆空樹,或者具有以下性質的二叉排序樹:它的左子樹和右子樹的深度之差(平衡因子)的絕對值不超過1,且它的左子樹和右子樹都是一顆平衡二叉樹。
棵AVL樹有如下必要條件:
條件一:它必須是二叉查找樹。
條件二:每個節點的左子樹和右子樹的高度差至多爲1。
在這裏插入圖片描述
圖一中左邊二叉樹的節點45的左孩子46比45大,不滿足二叉搜索樹的條件,因此它也不是一棵平衡二叉樹。右邊二叉樹滿足二叉搜索樹的條件,同時它滿足條件二,因此它是一棵平衡二叉樹。
在這裏插入圖片描述
左邊二叉樹的節點45左子樹高度2,右子樹高度0,左右子樹高度差爲2-0=2,不滿足條件二;右邊二叉樹的節點均滿足左右子樹高度差至多爲1,同時它滿足二叉搜索樹的要求,因此它是一棵平衡二叉樹。
如果mysql中的數據列構成的索引形成平衡二叉樹,那麼查詢效率比較高。但是數據的插入對樹的結構有很大影響,不一定會形成平衡二叉樹,比如:自增列,不斷插入過程中最終形成如下結構:
在這裏插入圖片描述
是一顆傾斜二叉樹,基於此樹查詢時,需要不斷遍歷每個節點,索引並沒有起到作用。
因此,mysql底層沒有使用二叉樹作爲索引數據結構。

1.3 紅黑樹

參考:http://www.360doc.com/content/18/0904/19/25944647_783893127.shtml
mysql並沒有使用紅黑樹作爲索引的數據結構。相對於二叉樹,只是做到了相對平衡,沒有做到絕對平衡,沒有實際解決二叉樹的確點。
在這裏插入圖片描述

1.4 B+Tree

目前大多數數據庫系統及文件系統都採用 B-Tree 或其變種 B+Tree 作爲索引結構。B+ 樹中的 B (balance)代表平衡,而不是二叉。B+ 樹是從最早的平衡二叉樹演化而來的。B+ 樹是由二叉查找樹、平衡二叉樹(AVLTree)和平衡多路查找樹(B-Tree)逐步優化而來。
一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程中就要產生磁盤 I/O 消耗,相對於內存存取,I/O 存取的消耗要高几個數量級,所以評價一個數據結構作爲索引的優劣最重要的指標就是在查找過程中磁盤 I/O 操作次數的漸進複雜度。換句話說,索引的結構組織要儘量減少查找過程中磁盤 I/O 的存取次數

利用網站製作的B+Tree:
在這裏插入圖片描述
可以看到,數據都在葉子節點上,並且葉子節點用指針串聯起來了,在遍歷的時候更快些。
在B+Tree中,所有數據記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只存儲key值信息

二、mysql索引的使用

存儲引擎是作用於表上的,目前比較常用的爲MYISAM和InnoDB

2.1 MyISAM的非聚集索引

那麼在MyISAM中是如何利用B+Tree索引組織數據的呢?什麼是非聚集索引呢?

使用MyISAM引擎儲存表數據會產生三個文件: .frm .MYD .MYI
如下圖:ti爲表名, .frm是存放表的定義信息(MyISAM和innoDB都有這個文件),
.MYD是存放具體的表的數據 ,.MYI就是存放該表的所有索引
在這裏插入圖片描述
那什麼又是非聚集索引呢?簡單來說就是索引文件和數據文件分開存儲,索引樹的葉子節點保存對應數據的地址,假設table表 有主鍵id和name(name列已經建立了索引),下面畫圖說明問題:

首先準備數據
在這裏插入圖片描述
對創建name列創建索引

create index idx_name on ti(name);
show index from ti;

在這裏插入圖片描述
下面這張圖就表面了在MyISAM下索引是如何工作的
在這裏插入圖片描述

信息量非常大,我來一一說明:這個索引樹是以建立索引的列的所有數據組織起來的,可以看出索引十分消耗存儲空間,而且葉子節點存儲的是對應的那行數據的地址,查找的時候先通過索引樹找到對應數據的地址,再通過地址找到真正的數據。這也就是爲什麼不把全部的索引一次性載入內存的原因, 索引太大了。

4.innoDB的聚集索引
innoDB的索引樹和MyISAM是有區別的,索引和數據放在同一個文件裏面。創建表是,生成的是兩個文件:.frm和.ibd, .frm是存放表的定義信息(MyISAM和innoDB都有這個文件),.ibd是用來存儲數據和索引的
主鍵索引樹的葉子節點直接存儲數據,所以叫做聚合索引。假設上面的表用的是InnoDB,建立了主鍵id索引和name這一列的索引,那麼數據又是如何組織起來的呢,下面畫圖說明:

在這裏插入圖片描述

可以看到在主鍵索引的葉子節點上直接存儲了對應的數據數據和索引在一起,聚合索引。而且其他的索引樹的葉子節點對應的是該行數據的主鍵id,如果以name進行查找,先在name的索引樹上找到對應的主鍵id,再通過得到的id進行查找。這樣是爲什麼innoDB查詢的時候比MyISAM慢的原因之一,innoDB必須涉及到主鍵索引,即佔用內存又直接多了一次主鍵索引樹的查找。

B+Tree的特性

(1)由圖能看出,單節點能存儲更多數據,使得磁盤IO次數更少。

(2)葉子節點形成有序鏈表,便於執行範圍操作。

(3)聚集索引中,葉子節點的data直接包含數據;非聚集索引中,葉子節點存儲數據地址的指針。

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