MyISAM和InnoDB是MySQL最經常使用的兩個存儲引擎,本文將進行詳盡的介紹和對比。對於MySQL其他幾種存儲引擎,請讀者自行搜索學習。mysql
本文會圖解兩種引擎的索引結構區別,而後講解索引的原理,理解本文內容,就可以理解索引優化的各類原則的背後緣由。算法
限於篇幅,本篇沒有介紹的知識,會在後續博客將逐一講解。例如:MySQL引擎的鎖機制、多列索引的生效規則、索引優化等主題。sql
下面SQL在本篇介紹引擎的結構區別時使用的表結構,便於讀者更好理解。數據庫
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '惟一碼',
`age` int(5) NOT NULL COMMENT '年齡',
`name` varchar(5) NOT NULL COMMENT '名字',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=92 DEFAULT CHARSET=utf8mb4;
複製代碼
B-樹、B樹和B-tree是同一個數據結構,只不過英語翻譯過來以後,有些人誤解了覺得是多種樹。因此好多講解樹的數據結構的博客徹底是誤導初學者。。。請讀者認真分辨。緩存
MyISAM和InnoDB的索引均採用B+樹數據結構,因此接下來先介紹一下B樹與B+樹。安全
B樹是一種多路搜索樹。bash
下圖是一個M=4階的B樹。數據結構
B樹的搜索,從根結點開始,對結點內的關鍵字(有序)序列進行二分查找,若是命中則結束,不然進入查詢關鍵字所屬範圍的兒子結點;重複,直到所對應的是葉子結點。併發
查找文件29的過程:nosql
B樹的特性:
下圖是一個M=3階的B+樹。
通常在數據庫系統或文件系統中使用的B+Tree結構都在經典B+Tree的基礎上進行了優化,增長了順序訪問指針。
B+樹是B樹的一種變形樹,總結起來,數據庫索引的B+樹與B樹的差別在於:
B+樹的特性:
解釋這個問題以前,須要瞭解一些基礎知識。
因爲存儲介質的特性,磁盤自己存取就比主存慢不少,再加上機械運動耗費,磁盤的存取速度每每是主存的幾百分之一,所以爲了提升效率,要儘可能減小磁盤I/O。爲了達到這個目的,磁盤每每不是嚴格按需讀取,而是每次都會預讀,即便只須要一個字節,磁盤也會從這個位置開始,順序向後讀取必定長度的數據放入內存。這樣作的理論依據是計算機科學中著名的局部性原理:
當一個數據被用到時,其附近的數據也一般會立刻被使用——程序運行期間所須要的數據一般比較集中。
因爲磁盤順序讀取的效率很高(不須要尋道時間,只需不多的旋轉時間),所以對於具備局部性的程序來講,預讀能夠提升I/O效率。
預讀的長度通常爲頁的整倍數。頁是計算機管理存儲器的邏輯塊,硬件及操做系統每每將主存和磁盤存儲區分割爲連續的大小相等的塊,每一個存儲塊稱爲一頁(在許多操做系統中,頁得大小一般爲4k),主存和磁盤以頁爲單位交換數據。當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會向磁盤發出讀盤信號,磁盤會找到數據的起始位置並向後連續讀取一頁或幾頁載入內存中,而後異常返回,程序繼續運行。
通常來講,磁盤I/O次數能夠用於評價索引結構的優劣。在B-Tree中查找,可知檢索一次最多須要訪問h個節點(上文舉例查找文件29的過程)。數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每一個節點只須要一次I/O就能夠徹底載入。
爲了達到這個目的,在實際實現中,B樹還使用以下技巧:
綜上所述,用B樹做爲索引結構效率是很是高的。
紅黑樹或者平衡二叉樹的其餘樹結構,
因此其餘樹結構的效率明顯比B樹差不少。
筆者認爲第三條緣由纔是MySQL使用B+樹而不是B樹作索引的主要緣由,畢竟MongoDB的索引是B樹,因此兩種數據結構並無絕對的好壞,要看實際的業務需求。
MyISAM在磁盤存儲上有三個文件,每一個文件名以表名開頭,擴展名指出文件類型。
MyISAM引擎使用B+樹做爲索引結果,葉節點的data域存放的是數據記錄的地址。
MyISAM索引文件和數據文件是分離的,索引文件僅保存記錄所在頁的指針(物理位置),經過這些地址來讀取頁,進而讀取被索引的行。
樹中葉子保存的是對應行的物理位置。經過該值,存儲引擎能順利地進行回表查詢,獲得一行完整記錄。同時,每一個葉子頁也保存了指向下一個葉子頁的指針。從而方便葉子節點的範圍遍歷。
在MyISAM中,主鍵索引和輔助索引在結構上沒有任何區別,只是主鍵索引要求key是惟一的,而輔助索引的key能夠重複。
MySQL5.5開始支持InnoDB引擎,並將其做爲默認數據庫引擎。
Innodb有兩種存儲方式,共享表空間存儲和多表空間存儲。
Innodb只有表結構文件和數據文件。
表結構文件和MyISAM同樣,以表名開頭,擴展名是.frm。
數據文件與存儲方式有關:
Innodb主鍵索引中,既存儲了主鍵值,又存儲了行數據。
對於輔助索引,InnoDB採用的方式是在葉子頁中保存主鍵值,經過這個主鍵值來回表(上圖)查詢到一條完整記錄,所以按輔助索引檢索實際上進行了二次查詢,效率確定是沒有按照主鍵檢索高的。
MyISAM存儲表分爲三個文件frm(表結構)、MYD(表數據)、MYI(表索引),而Innodb如上文所說,根據存儲方式不一樣,存儲結構不一樣。
MyISAM不支持事務,而Innodb支持事務,具備事務、回滾和恢復的事務安全。
MyISAM不支持外鍵,而Innodb支持外鍵。MyISAM容許沒有主鍵,可是Innodb必須有主鍵,若未指定主鍵,會自動生成長度爲6字節的主鍵。
MyISAM只支持表級鎖,而Innodb支持行級鎖,具備比較好的併發性能,可是行級鎖只有在where子句是對主鍵篩選才生效,非主鍵where會鎖全表
MyISAM使用B+樹做爲索引結構,葉節點保存的是存儲數據的地址,主鍵索引key值惟一,輔助索引key能夠重複,兩者在結構上相同。Innodb也是用B+樹做爲索引結構,數據表自己就是按照b+樹組織,葉節點key值爲數據記錄的主鍵,data域爲完整的數據記錄,輔助索引data域保存的是數據記錄的主鍵。
MongoDB不是傳統的關係性數據庫,而是以Json格式做爲存儲的nosql,目的就是高性能,高可用,易擴展。首先它擺脫了關係模型,因此範圍查詢和遍歷查詢的需求就沒那麼強烈了,其次Mysql因爲使用B+樹,數據都在葉節點上,每次查詢都須要訪問到葉節點,而MongoDB使用B-樹,全部節點都有Data域,只要找到指定索引就能夠進行訪問。
整體來講,Mysql選用B+樹和MongoDB選用B-樹仍是以本身的需求來選擇的。
用表中的普通列構建的索引,沒有任何限制
惟一索引列的值必須惟一,但容許有空值。若是是組合索引,則列值的組合必須惟一。
根據主鍵創建索引,不容許重複,不容許空值;
僅可用於MyISAM表,針對較大的數據,生成全文索引很是的消耗時間和空間(在生成FULLTEXT索引時,會爲文本生成一份單詞的清單,在索引時及根據這個單詞的清單來索引)。
又叫聯合索引。用多個列組合構建的索引,這多個列中的值不容許有空值。能夠在建立表的時候指定,也能夠修改表結構。
ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3');
爲了更多的提升mysql效率可創建組合索引,遵循」最左前綴「原則。建立複合索引時應該將最經常使用(頻率)做限制條件的列放在最左邊,依次遞減。示例的組合索引至關於創建了col1,col1col2,col1col2col3三個索引,而col2或者col3是不能使用索引的。
假設聯合索引由列(a,b,c)組成,則一下順序知足最左前綴規則:a、ab、abc;selece、where、order by 、group by均可以匹配最左前綴。其它狀況都不知足最左前綴規則就不會用到聯合索引。
定義:數據行的物理順序與列值(通常是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個彙集索引。
若是定義了主鍵,Innodb會選擇主鍵做爲彙集索引;若是沒有定義主鍵,Innodb會選擇不包含NULL值的惟一索引做爲彙集索引;若是也沒有這樣的惟一索引列,Innodb會選擇內置6字節長的rowID做爲隱含的彙集索引,這裏的RowId會隨着記錄的寫入而主鍵自增,可是它是不可引用和查看的,是數據庫引擎內部的使用。
若是咱們使用自增主鍵,那麼每次插入的新紀錄都在原先記錄的尾部按照順序,添加到當前節點的索引後面,當一頁快寫滿的時候,就會開闢一個新的頁。數據記錄自己就存與主索引的葉子節點上,B+tree的樹。這就要求每個葉子節點內的各條數據記錄按主鍵順序存放,所以每當有一條新的記錄插入的時候,MYSQL會根據其主鍵將其插入到合適的節點和位置上,若是頁面達到裝載因子(INNODB默認爲15/16),則開闢新的頁面(節點)
若是使用非自增主鍵(若是身份證號或學號等),因爲每次插入主鍵的值近似於隨機,所以每次新紀錄都要被插到現有索引頁得中間某個位置,此時MySQL不得不爲了將新記錄插到合適位置而移動數據,甚至目標頁面可能已經被回寫到磁盤上而從緩存中清掉,此時又要從磁盤上讀回來,這增長了不少開銷,同時頻繁的移動、分頁操做形成了大量的碎片,獲得了不夠緊湊的索引結構,後續不得不經過OPTIMIZE TABLE來重建表並優化填充頁面。
定義:該索引中索引的邏輯順序與磁盤上行的物理存儲順序不一樣,一個表中能夠擁有多個非彙集索引。
除了InnoDB的主鍵索引,在mysql中的其餘索引形式都是非彙集索引。
指從輔助索引中就能獲取到須要的記錄,而不須要查找主鍵索引中的記錄。使用覆蓋索引的一個好處是由於輔助索引不包括一條記錄的整行信息,因此數據量較彙集索引要少,能夠減小大量io操做。