上一篇回顧:數據庫
1.數據頁由七部分組成,包括File Header(描述頁的信息)、Page Header(描述數據的信息)、Infimum + Supremum(頁中的虛擬數據最大值和最小值)、User Records(用戶真實數據儲存的部分)、Free Space(真實數據增長劃分的部分空間)、Page Directory(頁中記錄相對位置,槽儲存的位置)、File Trailer(檢驗16kb大小的數據頁是否完整)。數據結構
2.每個頁中的數據都是單向鏈表,由數據的記錄頭信息next_record進行維護,記錄的是相對於本數據下一條數據的距離字節數。內存中的頁是雙向鏈表的數據結構,由頁信息的本頁號碼,上一頁號碼,下一頁號碼進行維護。大數據
3.頁中的數據都會進行分組,虛擬最小數據是一組,最大數據組最多存在8條數據,滿額是二分紅普通分組數據。每一個分組的最後一條數據相對於頁的偏移量就是槽的數據。本頁中數據的查找採用的就是二分法,經過槽肯定數據所在的分組,而後在進行搜索。blog
沒有索引的查找:排序
在一個頁中:索引
若是數據在一個頁中,採用的是以主鍵爲條件,那麼咱們就能夠採用二分法的方式進行尋找,咱們經過上一篇文章能夠知道的是每個頁中的數據都會進行分組,而後在頁信息的Page Diractory部分進行儲存槽的信息,經過槽定位到數據所在的分組,而後在開始進行數據的搜索。內存
若是咱們採用的不是主鍵做爲搜索的條件,那麼咱們經過二分法尋找的方法必然是行不通的了,這時候咱們只能很苦逼的一條一條數據慢慢的檢索。rem
在不少數據頁中:table
若是咱們要在不少數據頁中進行沒有索引的數據尋找那就更是不幸運了,只有一條數據的挨着進行搜索,假如咱們數據庫裏有上億的數據那麼就是很苦逼併且不現實的一種方式。搜索
索引的實現:
1:首先咱們先建立一個今天須要使用到的表格:
2:咱們進行數據的插入:
3:咱們用簡化的圖示展現一下這些數據儲存的狀態信息:
咱們在上一篇文章中提到過一個問題,那就是數據的有序性。咱們能夠從上圖看出一點端倪,那就是全部的數據都是以主鍵的大小值進行排列的。
4:假設咱們一頁只能儲存下三條數據,這是假設,一頁能夠儲存不少條數據,可是咱們在這裏爲了方便演示就假設只能儲存三條數據,而後咱們在新加入一數據:
咱們能夠看到的是咱們新插入的數據分了新的一頁,可是很奇怪的一點就是上一個頁的號碼是10,爲何下一頁就是28了?因此咱們必需要清楚一點,頁號碼是不連續的,咱們頁的雙向鏈表纔是維護頁秩序的鏈接,在前面咱們也提到過這個問題,使用的是File Header進行儲存頁碼,上一頁碼,下一頁碼。咱們在前面提到過一個問題那就是數據具備必定的順序,須要根據主鍵的大小進行排序,因此應該以下圖所示:
5:咱們如今搞清楚了數據的排布,那咱們在連續插入多條數據在直觀的看一下數據:
是否是發現了問題,咱們若是數據庫裏還有不少這樣的數據,就算是每一頁都是有槽的存在,能夠幫助咱們快速在同一頁中定位到數據所在。那麼,若是不在一頁咱們是否是隻有按照頁的雙向鏈表進行遍歷?答案很顯然不是,因此咱們須要對每一個頁建立新的東西。
6:目錄項:
咱們能夠看到的是咱們是否是建立了四個新的東西,這是啥?這就是目錄項,一個頁對應一個目錄項,目錄項裏面儲存的是頁碼+當前頁主鍵最小的值。到這裏是否是就有想法了?這玩意兒和咱們本身的數據是否是着實很像。還記得咱們在前面提過在數據的記錄頭信息的record_type這個屬性麼,0表示普通數據,1表示非葉子節點數據,2表示虛擬最小數據,3表示虛擬最大數據。因此,咱們本身的數據和這個目錄項數據的區分就是靠着這個屬性區分的。除了這個咱們的目錄項是沒有數據庫自動添加的三個列的。因此,咱們這時候是須要給這些目錄項分配一個頁,讓他們進行儲存:
7:到了這裏的時候咱們大概就能很清楚索引的結構了吧,那麼問題又來了,咱們的目錄項頁多了之後怎麼辦?那還能怎麼辦,繼續再建造上一層目錄項頁唄。使用當前目錄項的頁碼和當前頁最小目錄項的主鍵。
8:索引的查找就是經過一層一層的定位來實現的,最上層的頁咱們稱之爲根節點,中間的咱們稱之爲內節點,最底層的咱們稱之爲葉子節點。咱們就是經過頁中的槽二分法快速的定位數據所在頁或者組中,咱們在進行遍歷查找。最後說一點這玩意兒就是咱們說的B+樹,也沒多大點東西。
總結:
上面咱們講的就是Innodb儲存引擎爲每一個表都會建立的用主鍵進行構造的聚簇索引,聚簇索引就是全部數據都在葉子節點的索引。
二級索引:
講完聚簇索引咱們就來說一下什麼叫二級索引,二級索引顧名思義就是咱們本身建立的索引。有時候咱們的業務所須要,咱們要根據某個或者是某些字段進行查找,排序,分組等,這時候咱們爲了加快速度,那麼最好的方案就是建立這些列的索引:
咱們首先看葉子節點,它的構成就是經過的咱們須要使用的列+主鍵列構成,咱們以須要使用的列做爲排序的依據。而後咱們再看目錄項,是用咱們須要使用的列+頁碼組成。以此類推,咱們能夠得出的結論就是:
1.二級索引和聚簇索引的區別就是葉子節點不包括完整的數據
2.二級索引儲存的只是咱們須要使用到的列和主鍵,若是要其它列的數據怎麼辦?回表:就是經過二級索引獲取到的主鍵而後到聚簇索引裏面去進行查找。
聯合索引:
上面咱們看了一下聚簇索引和二級索引,接下來咱們再看一下什麼叫聯合索引,其實咱們能夠看出來就是聯合指的就是多列進行組合:咱們用c2和c3建立
咱們能夠看到的是聯合索引就是用多個字段進行建立索引,而後根據對應列順序進行排序。好比上圖咱們使用的就是c2和c3兩個列,因此咱們就是現根據c2進行排序,若是c2相同的狀況下咱們再根據c3進行排序。在這裏提早說一個注意點:聯合索引的使用務必要從最左邊也就是最早開始排序的列開始使用。下一篇文章咱們再詳細講。
Myisam儲存引擎的索引:
咱們原本主要使用的儲存引擎就是Innodb,可是本着知識的完整性,咱們介紹一下myisam儲存引擎的索引,其實一句話就說清楚了。myisam的索引的葉子節點是沒有保存真實數據的,只保存了主鍵的值。夠清楚了吧,這貨就是一個二級索引而已。
索引的建立和刪除語法:
1:在建表的時候建立索引:index和key二選其一便可
create tabel 表名(列信息) index|key 索引名(建立索引使用的列)
2:在修改表結構的時候咱們建立索引:
alter table 表名 add key|index 索引名(索引使用的列)
3:修改表結構刪除索引:
alter table 表名 drop key|index 索引名;