什么是索引
索引就是一種優化查詢的數據結構;
為什么要加索引
因為創建索引可以大大提高系統的查詢性能。
怎么提高查詢性能的
簡單的理解:一張數據量比較大的表格如果沒有添加任何索引,那我們在執行查詢的時候
就會是進行全表掃描,逐行比對,這樣的讀取效率肯定很低,如果我們為數據創建了索引
索引的實現方式又是支持快速查詢的這樣我們只需要先查詢索引中符合條件的,
然后再通過索引指向的數據行位置就可以實現快速定位數據了,不用全表掃描了。
索引存儲在什么地方
數據庫索引是存儲在磁盤上,當表中的數據量比較大時,索引的大小也跟着增長,達到幾個G甚至更多。
當我們利用索引進行查詢的時候,不可能把索引全部加載到內存中,只能加載一部分其他的都要從磁盤中讀取后加載到內存。
索引分哪些類型?
- 主鍵索引
一個列為設置為主鍵會默認創建一個主鍵索引。 - 唯一索引
嚴格來說主鍵索引是唯一索引的一種,這兩個的區別是:主鍵索引不允許為null,唯一索引可以為null; - 單列索引
- 復合索引
磁盤讀取的相關知識
- 什么時候會去讀取磁盤
當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會向磁盤發出讀盤信號,
磁盤會找到數據的起始位置並向后連續讀取一頁或幾頁載入內存中,然后異常返回,程序繼續運行 - 內存讀取磁盤的單位
上面提到的頁我們可以簡單理解是內存讀取磁盤數據中的最小單位。
后面的索引實現中樹中的每個節點大小往往和磁盤中一頁的大小相同,這是為了提高讀取的效率。 - 磁盤預讀和程序運行的局部原理
根據程序的局部性原理:當一個數據被使用,它附近的數據通常也會馬上被使用,所以為了減少磁盤io,
內存讀取磁盤數據的時候會順序向后預先讀取一定長度的數據放入內存。(頁的整數倍)
為什么哈希表、完全平衡二叉樹、B樹、B+樹都可以優化查詢,為何Mysql選擇B+樹?
哈希表
哈希表的兩個缺點:
- 哈希表可能會出現哈希沖突。
- 最主要的原因是它不支持范圍查詢。
完全平衡二叉樹
如圖如果一個樹的高度很大,如果查詢的數據剛好在葉子節點那經歷的磁盤Io的次數就是這個數的高度。
所以極端情況下平衡二叉樹也不是優選。
B-Tree
先說說幾個概念:
- 度(節點的數據存儲個數)也就是說B-Tree上的一個節點可以存儲多個數據。
- 葉節點具有相同的深度
- 葉節點的指針為空
- 節點中的數據從左到右遞增排列
這的確解決了樹的高度問題,因為:B-Tree的節點可以存儲多個值,高度肯定小於平衡二叉樹,磁盤io的次數也會少。
但是在范圍查找方面較比B+Tree差點。
題外話:B-Tree和BTree是一種樹。
B+Tree
B+Tree是B-Tree的變種,
B+樹的表示要比B樹要“胖”,原因在於B+樹中的非葉子節點會冗余一份在葉子節點中,並且葉子節點之間用指針相連。
-
mysql的實現中,B+Tree是把非葉子節點中只存儲索引,不存儲數據,只有葉子節點存儲數據,
這樣節點中的空間更多的存儲了索引,增加了度。最大程度的降低了樹的高度 -
加上一個節點的大小設置成為一頁或頁的倍數,一次磁盤io就可以讀出了一個節點中的很多數據,
加載到內存中再進行查找就很快了
所以最后總結:
使用B+Tree:可以提高查詢索引時的磁盤IO效率,並且可以提高范圍查詢的效率,並且B+樹里的元素也是有序的。
MyISAM和InnoDB的B+Tree實現
索引是數據庫引擎去實現的,在建立表的時候都會指定,數據庫引擎是一種插拔式的,根據自己的選擇去決定使用那個!
MyISAM索引實現(非聚集)
-
MYISAM中葉子節點的數據區域存儲的是數據記錄的地址。
MyISAM中的主鍵索引和輔助引是沒有區別的,其葉子節點存放的都是數據記錄的地址。
-
【MyISAM的索引文件和數據文件是分離的】
InnoDB的索引實現(聚集)
InnoDB中的葉子節點數據區域存儲的內容和主鍵索引和輔助索引是有區別的:
-
主鍵索引存儲的就是索引+數據(index+data)
Innodb的主鍵索引要比MyISAM的主鍵索引查詢效率要高,因為找到主鍵索引就找到了數據,MyISAM還有通過地址查詢一次。 -
輔助索引存儲的是主鍵的值
因此可以看出InnoDB的輔助索引會發生兩次,一次通過輔助索引查詢主鍵索引,一次是通過主鍵索引查詢到數據。 -
【InnoDB的索引文件是和數據文件放在一起的】
聚集索引和非聚集索引
聚集索引
數據行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個聚集索引。
-
聚集索引的葉子節點存放有對應的數據節點,可以直接獲取到對應的數據,
-
如果不創建索引,系統會自動創建一個隱含列作為表的聚集索引。
-
最好還是在創建表的時候添加聚集索引
-
在經常用於查詢或聚合條件的字段上建立聚集索引。這類查詢條件包括 between, >, <,group by, max,min, count等。
缺點: -
插入和更新索引的速度會比較慢,因為將會導致被更新的行移動。
非聚集索引
數據行的物理順序與列值的邏輯順序不相同,一個表中可以擁有多個非聚集索引。
-
葉子節點存放的不是實際數據,而是指向實際數據的指針。
-
聚集索引以外的索引都是非聚集索引,細分可以分為:普通索引,唯一索引,全文索引
注意:
InnoDB 主鍵使用的是聚簇索引,MyISAM 不管是主鍵索引,還是二級索引使用的都是非聚簇索引
創建索引的依據
什么樣的字段適合建索引
索引是建立在數據庫表中的某些列的上面。因此,在創建索引的時候,應該仔細考慮在哪些列上可以創建索引,在哪些列上不能創建索引。 一般來說,應該在具備下述特性的列上創建索引:
- 第一、在經常搜索的列上
- 第二、在主鍵上,強制該列的唯一性和組織表中數據的排列結構;
- 第三、在被用於連接(內連,外連)的字段上,主要是一些外鍵
- 第四、常被進行范圍搜索的列上,因為索引已經排序,其指定的范圍是連續的;
- 第五、經常參與排序的字段上,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;
- 第六、經常被用於作為條件查詢的字段上(WHERE子句中的列),加快條件的判斷速度。
建立索引,一般按照select的where條件來建立,
比如: select的條件是where f1 and f2,那么如果我們在字段f1或字段f2上建立索引是沒有用的,只有在字段f1和f2上同時建立索引才有用等。
什么樣的字段不適合建立索引
- 查詢中很少使用或者參考的列不應該創建索引
- 對於那些值為枚舉類的列也不應該增加索引,比如:性別,狀態,這是因為,由於這些列的取值很少,創建索引效果也不明顯。
- 對於那些定義為text, image和bit數據類型的列
記住這些可以提高索引的使用效率
資源
好博客:https://www.cnblogs.com/bypp/p/7755307.html
數據結構:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
面試必備之Mysql索引底層原理分析
為什么數據庫選B-tree或B+tree而不是二叉樹作為索引結構
關於B-樹問題的演示圖解