MYSQL索引爲何這麼快?瞭解索引的神奇之處

前言

公司最近組織開展一系列的技術分享會,我藉着此次機會把本身之前學的一些知識點從新概括一下記錄起來。首先是對本身技術的積累有好處,其次也是想讓本身學習的知識可以更深刻的理解,有不足或者錯誤的地方歡迎指出,共同進步。
探究一下MYSQL索引爲何這麼快?索引到底是什麼?mysql

1.什麼是索引?

  • MYSQL官方文檔介紹索引是一種方便快速查詢數據的數據結構。用咱們生活中的例子來說,索引就比如書的目錄,若是沒有目錄,每次你想要查找某些內容,你必須從頭開始查找,這樣的效率極其低下。
  • 索引通常比較大,因此大部分狀況下索引是存在磁盤的索引文件上,也有多是存在數據文件上。
  • 索引的種類有不少:主鍵索引(這是最多見的一種索引,主鍵不能爲空且必須惟一)、惟一索引(相對於主鍵索引,它的值能夠爲空)、全文索引(在char、varchar、text類型可使用)、普通索引、前綴索引。按照列數來區分:單一索引、組合索引(多字段組成)

2.MYSQL索引的數據結構

在講解MYSQL索引的數據結構以前,咱們先看看了解一下其餘的數據結構,看看他們的優缺點進行對比。程序員

2.1 二叉樹

二叉樹簡單來講就是左節點大於右節點,在理想的狀況下,他的查找速度就接近與二分法的性能O(log2n)。由於在內存排序的時間是很是快的,能夠忽略不計,因此總的消耗時間就取決於IO的操做次數。二叉樹查找速度取決樹高,每次查詢接口都是一次IO操做,也是性能的瓶頸所在。

可是也會有這種一種狀況,一樣也是二叉樹,可是他的樹很是高,致使查詢一次須要屢次IO操做,效率及其低下
sql

2.2 平衡二叉樹

平衡二叉樹能夠解決二叉樹不穩定致使查詢效率低下的缺點。平衡二叉樹的特色:樹的左右節點層級最高相差一層。在插入或者刪除的狀況下,經過左旋轉或右旋轉使得整個二叉樹平衡,不會出現層級相差不少的狀況。平衡二叉樹的性能接近二分法查找O(log2n)。

平衡二叉樹查找id爲8的記錄,只須要IO操做2次便可。可是仔細想一下,若是數據量不少呢?假設數據表有100W的數據,根據O(log2n)計算,大約須要20次IO操做。磁盤尋道大概須要10ms,總的查詢時間爲20 * 10 = 0.2,效率也比較低下。
還有就是平衡二叉樹不支持範圍查詢,範圍查詢每次都須要從根節點遍歷,效率及其低下。數據結構

2.3 B-樹(改造二叉樹成多叉樹)

以前的幾種樹形結構適合與小數據量的內存查找,也叫作內查找。在1970年,R.Bayer和E.Mccreight提出了一種適合於外查找的平衡多叉樹B-樹。MYSQL數據文件是存在磁盤的,每次都是按照一頁大小(通常而16K)讀取內存。像二叉樹、平衡二叉樹,每次讀取節點都要進行一次IO操做,因此樹越高IO操做次數越多。想要提升查詢效率,首先要解決的就是下降樹高的問題。
設想一下,每一次IO操做讀取一個節點,讀取16K大小的內存數據,可是每次節點的數據實際上遠遠小於16K。假設節點數據大小爲16B,爲了讓一次IO操做可以讀取更多節點,咱們能夠在每一個節點儘量地存儲索引數據。咱們在每一個節點存儲1000個索引數據(1000*16B = 16K),將二叉樹改形成多叉樹,從樹高變成樹「胖」,解決了樹高的問題,從而下降IO操做次數,提升查詢效率。

B-樹的特色:1.每一個節點存儲多個元素 2.節點的元素包含鍵值以及數據 3.全部葉子節點存放同一層,具備相同深度,葉子節點之間沒有指針鏈接。這種數據結構解決了樹高IO次數多的問題,可是在每一個節點存儲數據,假設數據一旦很大,每一個節點儲存的索引數也隨之減小,最後仍是會致使樹很高,查詢效率低。其次,B-樹不能範圍查詢。設想一下若是咱們要查詢15-25範圍內的數據,查到15以後就又要從新回到根節點繼續查找,這樣循環遍歷的效率有待提升。性能

2.4 B+樹(改造B-樹)

結合了B-樹的缺點進行改造,就誕生了B+樹。B+樹跟B-樹的差別並非很大,判斷的依據很簡單:節點是否存放數據。B+樹存放數據的節點只有葉子節點,並且葉子結點雙向指針鏈接,造成了雙向有序鏈表。

這樣一來,除了葉子節點其餘存放的都是索引鍵值,能夠很大程度增長節點存放索引樹,從理論上樹是要比B-樹「矮」的。同時B+樹支持範圍查詢,由於底層葉子節點是雙向有序鏈表,並且主鍵具備惟一性(對於輔助索引後面會講到),假設範圍爲15到19,咱們只須要查到15記錄以後繼續日後查詢,直到大於19便可,無需從根節點再次遍歷,效率較高。mysql索引

3.MYSQL索引B+樹實踐

MYISAM引擎 (主鍵索引)

MYISAM引擎是非聚簇索引,也就是說B+樹的葉子節點的鍵值存放索引列的值,數據存在數據在磁盤的地址。MYISAM的索引文件跟數據文件是分開存儲的。
CREATE TABLE student( id int(11) NOT NULL AUTO_INCREMENT, namevarchar(20) DEFAULT NULL, age int(11) DEFAULT NULL, PRIMARY KEY (id) USING BTREE, KEY idx_age (age) USING BTREE ) ENGINE = MyISAM AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8;
建立了一個表student,id爲主鍵索引,age爲普通索引。假設表中有如下數據,如今執行如下語句
SELECT * FROM stduent WHERE id = 16

具體鏈路:(實際上邏輯上相鄰實際磁盤並不必定相鄰,這裏只是方便展現)
(1)先從磁盤1加載數據到內存,由於18>16走左路(一次IO操做) (2)讀取磁盤2加載數據到內存,又由於16>14向下繼續讀取(一次IO操做) (3)檢索葉子節點,判斷到等於16則中止(一次IO操做)
學習

MYISAM引擎 (輔助索引)

在MYISAM引擎中,主鍵索引跟輔助索引的差異並不很大,葉子節點存放的都是磁盤地址,只是輔助索引並並非惟一值,因此在等值查詢檢索葉子節點的時候,也要按照範圍同樣,進行檢索數據。3d

Innodb引擎 (聚簇索引、主鍵索引)

Innodb引擎使用的是聚簇索引。每個數據表都有一個聚簇索引,採用B+樹的數據結構,葉子節點鍵值對應存放的是整行數據記錄。在Innodb中,非聚簇索引就是輔助索引,葉子節點存儲的數據是主鍵值。若是一個表沒有主鍵,innodb引擎會自動構建一個隱藏的rowid在構成聚簇索引。依舊是按照咱們剛剛講解MYISAM引擎的數據表例子:
SELECT * FROM stduent WHERE age = 37
指針

具體鏈路:(實際上邏輯上相鄰實際磁盤並不必定相鄰,這裏只是方便展現)
code

(1)先從磁盤1加載數據到內存,由於18<37走左路(一次IO操做) (2)讀取磁盤2加載數據到內存,又由於37>24向下繼續讀取(一次IO操做) (3)檢索葉子節點,判斷到等於37則中止(一次IO操做) (4)這時候查到的數據就是age字段爲37的記錄主鍵值。按照聚簇索引的方式再查找數據就獲得了數據結構集(這個過程叫作回表)相同索引字段狀況下,按主鍵字段排序。由於要多加上三次回表操做,效率回相對低一點點。這裏有個概念叫作覆蓋索引,若是查詢所須要的字段恰好就是索引字段就不須要回表查詢,從而提升了查詢效率。

總結

索引的原理遠遠不止於這麼一點點,組合索引以及一些其餘的原理我暫時理解還不是到位,等到後面學習更加理解以後再寫一篇文章進行記錄總結吧。「學而不思則惘,思而不學則殆」,之前沒辦法理解這句話的涵義,直到後來才知道總結、思考纔是學習最有效率的方式。多總結、多思考,也是做爲一名程序員進步的最快方式。

相關文章
相關標籤/搜索