做者:是虎子呀
https://my.oschina.net/u/4062...
以前有過一次面試,關於MySQL索引的原理及使用被面試官懟的體無完膚,立志要總結一番,而後一直沒有時間(實際上是懶……),準備好了嗎?java
數據庫索引,是數據庫管理系統(DBMS)中一個排序的數據結構,它能夠對數據庫表中一列或多列的值進行排序,以協助更加快速的訪問數據庫表中特定的數據。通俗的說,咱們能夠把數據庫索引比作是一本書前面的目錄,它能加快數據庫的查詢速度。python
思考:如何在一個圖書館中找到一本書?設想一下,假如在圖書館中沒有其餘輔助手段,只能一條道走到黑,一本書一本書的找,通過3個小時的連續查找,終於找到了你須要看的那本書,但此時天都黑了。mysql
爲了不這樣的事情,每一個圖書館才都配備了一套圖書館管理系統,你們要找書籍的話,先在系統上查找到書籍所在的房屋編號、圖書架編號還有書在圖書架幾層的那個方位,而後就能夠直接大搖大擺的去取書了,就能夠很快速的找到咱們所須要的書籍。索引就是這個原理,它能夠幫助咱們快速的檢索數據。面試
通常的應用系統對數據庫的操做,遇到最多、最容易出問題是一些複雜的查詢操做,當數據庫中數據量很大時,查找數據就會變得很慢,這樣就很影響整個應用系統的效率,咱們就可使用索引來提升數據庫的查詢效率。算法
目前大部分數據庫系統及文件系統都採用B-Tree或其變種B+Tree做爲索引結構, 我在這裏分別講一下。[](http://mp.weixin.qq.com/s?__b...:爲何索引能提升查詢速度?sql
即B樹,注意(不是B減樹),B樹是一種多路搜索樹。使用B-Tree結構能夠顯著減小定位記錄時所經歷的中間過程,從而加快存取速度。數據庫
B-Tree有以下一些特徵:後端
有關b樹的一些特性:微信
B樹的搜索:從根結點開始,對結點內的關鍵字(有序)序列進行二分查找,若是命中則結束,不然進入查詢關鍵字所屬範圍的兒子結點;重複執行這個操做,直到所對應的節點指針爲空,或者已是是葉子結點。數據結構
例以下面一個B樹,那麼查找元素43的過程以下:
根據根節點指針找到1八、37所在節點,把此節點讀入內存,進行第一次磁盤IO,此時發現43>37,找到指針p3。
根據指針p3,找到4二、51所在節點,把此節點讀入內存,進行第二次磁盤IO,此時發現42<43<51,找到指針p2。
根據指針p2,找到4三、46所在節點,把此節點讀入內存,進行第三次磁盤IO,此時咱們就已經查到了元素43。
在此過程總共進行了三次磁盤IO。
B+Tree屬於B-Tree的變種。與B-Tree相比,B+Tree有如下不一樣點:
關於MySQL的兩種經常使用存儲引擎MyISAM和InnoDB的索引均以B+樹做爲數據結構,兩者卻有不一樣(這裏只說兩者索引的區別)。推薦看下:InnoDB一棵B+樹能夠存放多少行數據?
MyISAM使用B+樹做爲索引結構,葉節點葉節點的data域保存的是存儲數據的地址,主鍵索引key值惟一,輔助索引key能夠重複,兩者在結構上相同。關注微信公衆號:Java技術棧,在後臺回覆:mysql,能夠獲取我整理的 N 篇 MySQL 教程,都是乾貨。
所以,MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,若是要找的Key存在,則取出其data域的值,而後以data域的值爲地址,去讀取相應數據記錄 。所以,索引文件和數據文件是分開的,從索引中檢索到的是數據的地址,而不是數據。
Innodb也是用B+樹做爲索引結構,但具體實現方式卻與MyISAM大相徑庭,首先,數據表自己就是按照b+樹組織,因此數據文件自己就是主鍵索引文件。葉節點key值爲數據表的主鍵,data域爲完整的數據記錄。
所以InnoDB表數據文件自己就是主鍵索引(這也就是MyISAM能夠容許沒有主鍵,可是Innodb必須有主鍵的緣由)。第二個與MyISAM索引的不一樣是InnoDB的輔助索引的data域存儲相應數據記錄的主鍵值而不是地址。換句話說,InnoDB的全部輔助索引都引用主鍵做爲data域。
普通索引:(由關鍵字KEY或INDEX定義的索引)的惟一任務是加快對數據的訪問速度。
惟一索引:普通索引容許被索引的數據列包含重複的值,而惟一索引不容許,可是能夠爲null。因此任務是保證訪問速度和避免數據出現重複。
主鍵索引:在主鍵字段建立的索引,一張表只有一個主鍵索引。
組合索引:多列值組成一個索引,專門用於組合搜索。
全文索引:對文本的內容進行分詞,進行搜索。(MySQL5.6及之後的版本,MyISAM和InnoDB存儲引擎均支持全文索引。)推薦看下:MySQL 索引B+樹原理,以及建索引的幾大原則。
主鍵自動創建惟一索引。
常常做爲查詢條件在WHERE或者ORDER BY 語句中出現的列要創建索引。
查詢中與其餘表關聯的字段,外鍵關係創建索引。
常常用於聚合函數的列要創建索引,如min(),max()等的聚合函數。
常常增刪改的列不要創建索引。
有大量重複的列不創建索引。
表記錄太少不要創建索引,由於數據較少,可能查詢所有數據花費的時間比遍歷索引的時間還要短,索引就可能不會產生優化效果 。
創建聯合索引的時候都會默認從最左邊開始,因此索引列的順序很重要,創建索引的時候就應該把最經常使用的放在左邊,使用select的時候也是這樣,從最左邊的開始,依次匹配右邊的。
能夠保證數據庫表中每一行的數據的惟一性。
能夠大大加快數據的索引速度。
加速表與表之間的鏈接。
能夠顯著的減小查詢中分組和排序的時間。
建立索引和維護索引要耗費時間,這種時間隨着數據量的增長而增長。
索引須要佔物理空間,除了數據表佔用數據空間以外,每個索引還要佔用必定的物理空間,若是須要創建聚簇索引,那麼須要佔用的空間會更大,其實創建索引就是以空間換時間。
表中的數據進行增、刪、改的時候,索引也要動態的維護,這就下降了維護效率。
建立測試表index_test
使用python腳本程序經過pymsql模塊,向表中添加十萬條數據
import pymysql def main(): # 建立Connection鏈接 conn = pymysql.connect(host='localhost', port=3306, database='db_test', user='root', password='deepin', charset='utf8') # 得到Cursor對象 cursor = conn.cursor() # 插入10萬次數據 for i in range(100000): cursor.execute("insert into index_test values('haha-%d')" % i) # 提交數據 conn.commit() if __name__ == "__main__": main()
在mysql終端開啓運行時間監測:set profiling=1;
查找第1萬條數據ha-99999
select * from index_test where name='haha-99999';
查看執行的時間:
show profiles;
爲表index_test的name列建立索引:
create index name\_index on index\_test(name(10));
再次執行查詢語句、查看執行的時間:
能夠看出合適的索引確實能夠明顯提升某些字段的查詢效率。
最後,感謝女友在生活中,工做上的包容、理解與支持 !
推薦去個人博客閱讀更多:
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
以爲不錯,別忘了點贊+轉發哦!