資料庫索引詳解
1.什麼是索引?索引的常見型別有什麼?
索引就是加快檢索表中資料的方法。資料庫的索引類似於書籍的索引。在書籍中,索引允許使用者不必翻閱完整個書就能迅速地找到所需要的資訊。在資料庫中,索引也允許資料庫程式迅速地找到表中的資料,而不必掃描整個資料庫。
分類:這裡我們主要介紹常見的聚集索引和非聚集索引
聚集索引:對正文內容按照一定規則排列的目錄稱為聚集索引
非聚集索引:目錄自己按照一定規則排列,正文自己按照另一種規則排列,目錄主要是儲存對正文的一個對映關係,這種稱為非聚集索引
看完上邊的定義,你可能對聚集索引和非聚集索引還是一頭霧水,沒關係,看看下邊的例子你應該就明白了
以我們的漢語字典為例,我們要查一個字“愛”,我們知道它的發音,我們會自然的翻開目錄中的A目錄下去找讀音為“ai"的字,找到它並找到它具體對應到哪一頁,這裡A目錄下所有字具體在哪一頁都是連續的,假設A目錄下”愛“對應18頁,在A目錄中”愛”的前一個字是“矮”,對應的是17頁,也就是他們在目錄中的相對順序也是他們在具體頁數中的相對順序,這個就是聚集索引。
但是如果我們遇到一個字,並不知道它的讀音,我們就會採用另一種查詢方式,根據“偏旁部首”去查詢,然後根據這個字後的頁碼直接翻到某頁來找到您要找的字。但你結合“部首目錄”和“檢字表”而查到的字的排序並不是真正的正文的排序方法,比如你查“張”字,我們可以看到在查部首之後的檢字表中“張”的頁碼是672頁,檢字表中“張”的上面是“馳”字,但頁碼卻是63頁,“張”的下面是“弩”字,頁面是390頁,這樣目錄中的排列方式並不是正文實際的排列方式,這就是非聚集索引。
2.索引採取什麼資料結構儲存?為什麼採取這樣的資料結構?
大規模的資料不可能全部儲存在記憶體中,故要儲存到磁碟上,這樣查詢讀取等操作時就涉及到磁碟IO,那麼索引就要儘量減少磁碟IO次數,才能保證查詢速度。如果採用普通的二叉查詢樹結構,會由於樹的高度過深進行多次磁碟IO,導致查詢效率低下,那麼就要儘量減少樹的高度,這就引出了B-Tree和B+-Tree,即B樹和B+樹。
總結:為什麼使用B+樹?
1.檔案很大,不可能全部儲存在記憶體中,故要儲存到磁碟上 2.索引的結構組織要儘量減少查詢過程中磁碟I/O的存取次數(為什麼使用B-/+Tree,還跟磁碟存取原理有關,具體看下邊分析) 3. 區域性性原理與磁碟預讀,預讀的長度一般為頁(page)的整倍數,(在許多作業系統中,頁得大小通常為4k) 4. 資料庫系統巧妙利用了磁碟預讀原理,將一個節點的大小設為等於一個頁,這樣 每個節點只需要一次I/O 就可以完全載入,(由於節點中有兩個陣列,所以地址連續)。而紅黑樹這種結構, h 明顯要深的多。由於邏輯上很近的節點(父子)物理上可能很遠,無法利用區域性性磁碟的構造
磁碟是一個扁平的圓盤。盤面上有許多稱為磁軌的圓圈,資料就記錄在這些磁軌上。磁碟可以是單片的,也可以是由若干碟片組成的盤組,每一碟片上有兩個面。如上圖11.3中所示的6片盤組為例,除去最頂端和最底端的外側面不儲存資料之外,一共有10個面可以用來儲存資訊
當磁碟驅動器執行讀/寫功能時。碟片裝在一個主軸上,並繞主軸高速旋轉,當磁軌在讀/寫頭(又叫磁頭) 下通過時,就可以進行資料的讀 / 寫了。
一般磁碟分為固定頭盤(磁頭固定)和活動頭盤。固定頭盤的每一個磁軌上都有獨立的磁頭,它是固定不動的,專門負責這一磁軌上資料的讀/寫。
活動頭盤 (如上圖)的磁頭是可移動的。每一個盤面上只有一個磁頭(磁頭是雙向的,因此正反盤面都能讀寫)。它可以從該面的一個磁軌移動到另一個磁軌。所有磁頭都裝在同一個動臂上,因此不同盤面上的所有磁頭都是同時移動的(行動整齊劃一)。當碟片繞主軸旋轉的時候,磁頭與旋轉的碟片形成一個圓柱體。各個盤面上半徑相同的磁軌組成了一個圓柱面,我們稱為柱面。因此,柱面的個數也就是盤面上的磁軌數。
磁碟的讀寫原理及效率
磁碟上的資料需要使用一個三維地址來表示:柱面號、盤面號和塊號
讀/寫磁碟的三個步驟:
(1) 首先移動臂根據柱面號使磁頭移動到所需要的柱面上,這一過程被稱為定位或查詢。
(2) 如上圖11.3中所示的6盤組示意圖中,所有磁頭都定位到了10個盤面的10條磁軌上(磁頭都是雙向的)。這時根據盤面號來確定指定盤面上的磁軌。
(3) 盤面確定以後,碟片開始旋轉,將指定塊號的磁軌段移動至磁頭下。
耗費時間:
- 查詢時間:即完成步驟(1)的時間,這部分耗時最多
- 等待時間:即完成步驟(3)的時間
- 傳輸時間:資料通過系統匯流排送到記憶體的時間
- 根據根結點指標找到檔案目錄的根磁碟塊1,將其中的資訊匯入記憶體。【磁碟IO操作 1次】
- 此時記憶體中有兩個檔名17、35和三個儲存其他磁碟頁面地址的資料。根據演算法我們發現:17<29<35,因此我們找到指標p2。
- 根據p2指標,我們定位到磁碟塊3,並將其中的資訊匯入記憶體。【磁碟IO操作 2次】
- 此時記憶體中有兩個檔名26,30和三個儲存其他磁碟頁面地址的資料。根據演算法我們發現:26<29<30,因此我們找到指標p2。
- 根據p2指標,我們定位到磁碟塊8,並將其中的資訊匯入記憶體。【磁碟IO操作 3次】
- 此時記憶體中有兩個檔名28,29。根據演算法我們查詢到檔名29,並定位了該檔案記憶體的磁碟地址。
當然,如果我們使用平衡二叉樹的磁碟儲存結構來進行查詢,磁碟4次,最多5次,而且檔案越多,B樹比平衡二叉樹所用的磁碟IO操作次數將越少,效率也越高。(這裡需要重點解釋一下,為什麼使用平衡二叉樹會有更多的IO操作,個人理解是假設記憶體一次載入的盤塊大小固定,上圖中我們已經假設了一個盤塊剛好只能儲存一個三叉樹結點大小,如果換成是二叉樹,則相比每次讀取的關鍵字少,所以需要更多次的IO)
B+-Tree
B+樹是B樹的一種變形,這裡要注意B+樹的兩個重要特點:
1.所有葉子節點包含了全部關鍵字的資訊,以及指向這些關鍵字記錄的指標,且葉子節點本身依關鍵字的大小自小而大的順序連結
2.所有非終端節點可以看成是索引,節點中僅含有其子樹根節點最大(或最小)的關鍵字,不包含查詢的有效資訊(B樹則包含)
為什麼B+樹比B 樹更適合實際應用中作業系統的檔案索引和資料庫索引?
1) B+-tree的磁碟讀寫代價更低
B+的內部結點並沒有指向關鍵字具體資訊的指標。因此其內部結點相對B 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入記憶體中的需要查詢的關鍵字也就越多。相對來說IO讀寫次數也就降低了。
舉個例子,假設磁碟中的一個盤塊容納16bytes,而一個關鍵字2bytes,一個關鍵字具體資訊指標2bytes。一棵9階B樹(一個結點最多8個關鍵字)的內部結點需要2個盤快。而B+ 樹內部結點只需要1個盤快。當需要把內部結點讀入記憶體中的時候,B 樹就比B+ 樹多一次盤塊查詢時間(在磁碟中就是碟片旋轉的時間)。
2) B+-tree的查詢效率更加穩定
由於非終結點並不是最終指向檔案內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查詢必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。
3.B+樹索引和雜湊索引區別
如果是等值查詢,那麼雜湊索引明顯有絕對優勢,因為只需要經過一次演算法即可找到相應的鍵值;當然了,這個前提是,鍵值都是唯一的。如果鍵值不是唯一的,就需要先找到該鍵所在位置,然後再根據連結串列往後掃描,直到找到相應的資料從示意圖中也能看到。
如果是範圍查詢檢索,這時候雜湊索引就毫無用武之地了,因為原先是有序的鍵值,經過雜湊演算法後,有可能變成不連續的了,就沒辦法再利用索引完成範圍查詢檢索;
同理,雜湊索引也沒辦法利用索引完成排序,以及like ‘xxx%’ 這樣的部分模糊查詢(這種部分模糊查詢,其實本質上也是範圍查詢);
雜湊索引也不支援多列聯合索引的最左匹配規則;
B+樹索引的關鍵字檢索效率比較平均,不像B樹那樣波動幅度大,在有大量重複鍵值情況下,雜湊索引的效率也是極低的,因為存在所謂的雜湊碰撞問題。
4.InnoDB和MyISAM儲存引擎
InnoDB的主索引:主索引的key是資料表的主鍵,因此InnoDB表資料檔案本身就是主索引,所以必須有主鍵,如果沒有顯示定義,自動為生成一個隱含欄位作為主鍵InnoDB的輔助索引:輔助索引也會包含主鍵列,比如名字建立索引,內部節點 會包含名字,葉子節點會包含該名字對應的主鍵的值(下圖以名字做一個輔助索引)
MyISAM主索引和輔助索引在結構上沒有任何區別,只是主索引要求key是唯一的,輔助索引可以重複,其葉子節點儲存都是資料記錄的地址
主索引:
輔助索引:
InnoDB索引和 MyISAM索引 的區別:
一是主索引的區別,InnoDB的資料檔案本身就是索引檔案(聚集索引),而MyISAM的索引和資料是分開的(非聚集索引)。
二是輔助索引的區別:InnoDB的輔助索引data域儲存相應記錄主鍵的值而不是地址。而MyISAM的輔助索引和主索引沒有多大區別。