公司最近組織開展一系列的技術分享會,我藉着此次機會把本身之前學的一些知識點從新概括一下記錄起來。首先是對本身技術的積累有好處,其次也是想讓本身學習的知識可以更深刻的理解,有不足或者錯誤的地方歡迎指出,共同進步。
探究一下MYSQL索引爲何這麼快?索引到底是什麼?mysql
在講解MYSQL索引的數據結構以前,咱們先看看了解一下其餘的數據結構,看看他們的優缺點進行對比。程序員
二叉樹簡單來講就是左節點大於右節點,在理想的狀況下,他的查找速度就接近與二分法的性能O(log2n)。由於在內存排序的時間是很是快的,能夠忽略不計,因此總的消耗時間就取決於IO的操做次數。二叉樹查找速度取決樹高,每次查詢接口都是一次IO操做,也是性能的瓶頸所在。
可是也會有這種一種狀況,一樣也是二叉樹,可是他的樹很是高,致使查詢一次須要屢次IO操做,效率及其低下
sql
平衡二叉樹能夠解決二叉樹不穩定致使查詢效率低下的缺點。平衡二叉樹的特色:樹的左右節點層級最高相差一層。在插入或者刪除的狀況下,經過左旋轉或右旋轉使得整個二叉樹平衡,不會出現層級相差不少的狀況。平衡二叉樹的性能接近二分法查找O(log2n)。
平衡二叉樹查找id爲8的記錄,只須要IO操做2次便可。可是仔細想一下,若是數據量不少呢?假設數據表有100W的數據,根據O(log2n)計算,大約須要20次IO操做。磁盤尋道大概須要10ms,總的查詢時間爲20 * 10 = 0.2,效率也比較低下。
還有就是平衡二叉樹不支持範圍查詢,範圍查詢每次都須要從根節點遍歷,效率及其低下。數據結構
以前的幾種樹形結構適合與小數據量的內存查找,也叫作內查找。在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以後就又要從新回到根節點繼續查找,這樣循環遍歷的效率有待提升。性能
結合了B-樹的缺點進行改造,就誕生了B+樹。B+樹跟B-樹的差別並非很大,判斷的依據很簡單:節點是否存放數據。B+樹存放數據的節點只有葉子節點,並且葉子結點雙向指針鏈接,造成了雙向有序鏈表。
這樣一來,除了葉子節點其餘存放的都是索引鍵值,能夠很大程度增長節點存放索引樹,從理論上樹是要比B-樹「矮」的。同時B+樹支持範圍查詢,由於底層葉子節點是雙向有序鏈表,並且主鍵具備惟一性(對於輔助索引後面會講到),假設範圍爲15到19,咱們只須要查到15記錄以後繼續日後查詢,直到大於19便可,無需從根節點再次遍歷,效率較高。mysql索引
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引擎中,主鍵索引跟輔助索引的差異並不很大,葉子節點存放的都是磁盤地址,只是輔助索引並並非惟一值,因此在等值查詢檢索葉子節點的時候,也要按照範圍同樣,進行檢索數據。3d
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的記錄主鍵值。按照聚簇索引的方式再查找數據就獲得了數據結構集(這個過程叫作回表)相同索引字段狀況下,按主鍵字段排序。由於要多加上三次回表操做,效率回相對低一點點。這裏有個概念叫作覆蓋索引,若是查詢所須要的字段恰好就是索引字段就不須要回表查詢,從而提升了查詢效率。
索引的原理遠遠不止於這麼一點點,組合索引以及一些其餘的原理我暫時理解還不是到位,等到後面學習更加理解以後再寫一篇文章進行記錄總結吧。「學而不思則惘,思而不學則殆」,之前沒辦法理解這句話的涵義,直到後來才知道總結、思考纔是學習最有效率的方式。多總結、多思考,也是做爲一名程序員進步的最快方式。