mysql之索引詳解

mysql索引

一、存儲引擎

mysql存儲引擎有以下幾種類型:myisam、innodb、csv、memory等,當然常用的還是myisam和innodb

myisam和innodb的區別

區別 myisam innodb
事務 不支持    支持
外鍵 不支持 支持
類型 非聚集索引 聚集索引
具體行數 有存儲 全表掃描
最小的鎖粒度 表鎖 行鎖

所以 MySQL5.5版本開始Innodb已經成爲Mysql的默認引擎(之前是MyISAM),說明其優勢是有目共睹的。如果你不知道用什麼存儲引擎,那就用InnoDB,至少不會差

二、物理位置

在物理存儲上,一個數據庫對應一個文件夾

數據庫文件存儲的位置:my.ini配置文件中,datadir對應的數據目錄位置

myisam每個表對應三個文件

*.MYI:存放的是數據表對應的索引信息和索引內容;

*.FRM:存放的是數據表的結構信息;

*.MYD:存放的是數據表的內容;

InnoDB每一張表對應一個文件

*.frm 存放的是數據表的的結構信息

*數據內容和索引文件都是統一存放在ibdata文件中.

所以索引文件都是額外進行存放的,對應索引的查詢以及維護都是需要消耗IO的;

三、索引類型

普通索引

最基本的索引,沒有任何使用限制

唯一索引

與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一

主鍵索引

是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值。一般是在建表的時候同時創建主鍵索引

組合索引

指多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引纔會被使用。使用組合索引時遵循最左前綴集合

全文索引

一般使用在全文搜索上,主要用來查找文本中的關鍵字,而不是直接與索引中的值相比較。fulltext索引跟其它索引大不相同,它更像是一個搜索引擎,而不是簡單的where語句的參數匹配。

四、索引注意事項

1.索引不包含null值的列,所以我們在數據庫設計時不要讓字段默認值爲null

2.短索引,如果一個字段char(255)的列表,前15個字段多數值是唯一的,就不要對列進行索引。短索引可以提高查詢速度和節省I/O操作

3.索引列排序,查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。因此數據庫默認排序可以符合要求的情況下不要使用排序操作;儘量不要包含多個列的排序,如果需要最好給這些列創建複合索引。

4.like語句,一般情況下不推薦使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引而like “aaa%”可以使用索引。

5.不要在列上進行運算,這將導致索引失效而進行全表掃描,例如

SELECT * FROM table_name WHERE YEAR(column_name)<2017;

6.不使用not in和<>操作

五、索引底層結構

1.查詢算法

索引的作用是做數據的快速檢索,而快速檢索的實現的本質是數據結構。通過不同數據結構的選擇,實現各種數據快速檢索。在數據庫中,高效的查找算法是非常重要的,因爲數據庫中存儲了大量數據,一個高效的索引能節省巨大的時間

2.哈希表

哈希算法:也叫散列算法,就是把任意值(key)通過哈希函數變換爲固定長度的 key 地址,通過這個地址進行具體數據的數據結構

假設我們要取出id=7的數據,哈希算法首先計算存儲 id=7 的數據的物理地址 addr=hash(7)=4231,而 4231 映射的物理地址是 0x77,0x77 就是 id=7 存儲的數據的物理地址,通過該獨立地址可以找到對應 user_name='g'這個數據。這就是哈希算法快速檢索數據的計算過程

拓展:數據碰撞問題?時間複雜度  O(1) ?範圍怎麼查詢?

3.二叉樹

二叉查找樹的時間複雜度是 O(lgn),比如針對下面這個二叉樹結構,我們需要計算比較 3 次就可以檢索到 id=7 的數據,相對於直接遍歷查詢省了一半的時間,從檢索效率上看來是能做到高速檢索的。此外二叉樹的結構也能解決哈希索引不能提供的範圍查找功能

但是我們需要思考在數據庫中,數據的自增是一個很常見的形式,比如一個表的主鍵是 id,而主鍵一般默認都是自增的,如果採取二叉樹這種數據結構作爲索引,那下面的極端的圖是不是必然出現,然後時間複雜度是否變成了N?

4.紅黑樹

針對二叉樹的極端情況, 我們可以讓樹節點的自動旋轉和調整,讓二叉樹始終保持基本平衡的狀態

紅黑樹就會自動左旋右旋節點以及節點變色,調整樹的形態,使其保持基本的平衡狀態(時間複雜度爲 O(logn)),也就保證了查找效率不會明顯減低。比如從 1 到 7 升序插入數據節點,如果是普通的二叉查找樹則會退化成鏈表,但是紅黑樹則會不斷調整樹的形態,使其保持基本平衡狀態,如下圖所示。下面這個紅黑樹下查找 id=7 的所要比較的節點數爲 4,依然保持二叉樹不錯的查找效率。

5. AVL 樹

AVL樹其實就是不斷調整,最終絕對平衡。 也正是因爲 AVL 樹是個絕對平衡的二叉樹,因此他在調整二叉樹的形態上消耗的性能會更多。

目前可以滿足查詢需求了,不錯的查找性能(O(logn)),不存在極端的低效查找的情況。可以實現範圍查找、數據排序。

但是

數據庫查詢數據的瓶頸在於磁盤 IO,如果使用的是 AVL 樹,我們每一個樹節點只存儲了一個數據,我們一次磁盤 IO 只能取出來一個節點上的數據加載到內存裏,那比如查詢 id=7 這個數據我們就要進行磁盤 IO 三次,這是多麼消耗時間的。所以我們設計數據庫索引時需要首先考慮怎麼儘可能減少磁盤 IO 的次數。

磁盤 IO 有個有個特點,就是從磁盤讀取 1B 數據和 1KB 數據所消耗的時間是基本一樣的,我們就可以根據這個思路,我們可以在一個樹節點上儘可能多地存儲數據,一次磁盤 IO 就多加載點數據到內存,這就是 B 樹,B+樹的的設計原理了。

6.B樹

下面這個 B 樹,每個節點限制最多存儲兩個 key,一個節點如果超過兩個 key 就會自動分裂。比如下面這個存儲了 7 個數據 B 樹,只需要查詢兩個節點就可以知道 id=7 這數據的具體位置,也就是兩次磁盤 IO 就可以查詢到指定數據,優於 AVL 樹。

但是考慮到磁盤 IO 讀一個數據和讀 100 個數據消耗的時間基本一致,那我們的優化思路就可以改爲:儘可能在一次磁盤 IO 中多讀一點數據到內存。這個直接反映到樹的結構就是,每個節點能存儲的 key 可以適當增加。

7.B+樹

B 樹和 B+樹有什麼不同呢?

第一,B 樹一個節點裏存的是數據,而 B+樹存儲的是索引(地址),所以 B 樹裏一個節點存不了很多個數據,但是 B+樹一個節點能存很多索引,B+樹葉子節點存所有的數據。

第二,B+樹的葉子節點是數據階段用了一個鏈表串聯起來,便於範圍查找。

通過 B 樹和 B+樹的對比我們看出,B+樹節點存儲的是索引,在單個節點存儲容量有限的情況下,單節點也能存儲大量索引,使得整個 B+樹高度降低,減少了磁盤 IO。其次,B+樹的葉子節點是真正數據存儲的地方,葉子節點用了鏈表連接起來,這個鏈表本身就是有序的,在數據範圍查找時,更具備效率。因此 Mysql 的索引用的就是 B+樹,B+樹在查找效率、範圍查找中都有着非常不錯的性能。

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