本文是針對Mysql索引原理剖析的入門級文章 ,主要圍繞如下四個話題展開對索引相關原理的描述。mysql
一丶索引基本概念
二丶(B+)-Tree索引基本實現
三丶關於Mysql索引常見術語解疑(聚族索引,非聚族索引,最左前綴原則, 索引覆蓋,哈希索引,自適應哈希索引)
四丶索引侷限性
一丶索引基本概念
對照着生活中的概念,數據庫索引的概念理解起來比較容易。數據庫的索引至關於書籍的目錄。sql
書籍目錄: 查閱書籍內容時可對照着目錄,直接定位到想查閱內容的具體頁數,避免逐頁翻書的工做量
數據庫索引: 某條查詢sql語句能夠對照數據表中的索引,直接定位到符合查詢條件的數據行的物理地址,避免對數據表進行全表掃描的工做。 上述概念關於索引的概念很簡單,可是包含了不少的信息量。進一步挖掘以下:
索引是創建數據表上的,每張數據表均可以有本身的索引。而且數據表中的索引能夠有多個,可是不能設置重複的索引。
索引更具體一點來講,其是創建在數據表的相關列上, 畢竟只有索引創建在列上才能和查詢條件相關聯嘛。若索引在一個列上創建稱爲單一索引,若索引在多個列上創建成爲複合索引。在表table1中的col1,col2,col3列上創建名爲indx1的索引的sql語句以下: create index idx1 on table1(col1,col2,col3) 這裏須要特別注意,索引和創建索引時的數據列順序有關,好比在col3,col2,col1這三個列上創建名爲idx2的索引和上述idx1索引是不一樣的索引。這是一個很是重要的概念
索引是一個獨立於數據表的結構,就像書籍同樣,目錄和正文分屬於不一樣的部分。數據表的內容發生了改變了,那麼索引的結構也會發生相應調整,簡而言之,索引的更新和數據表內容的更新保持一致。 該條具體一點就是,在對創建了索引的相關列進行增刪改操做時,會附加維護索引結構的相關操做。未創建索引的列則不須要考慮這個性能消耗。
索引提升查詢的性能,索引經過避免全表掃描,減小掃描行的數量來提升查詢的性能。
對於一條簡單的查詢來講,是如何使用索引查詢的呢? select * from table1 where col1 = A and col2 = B and col3 = C 這條查詢就利用idx1這個索引。目前來看,很是簡單查詢條件和索引列徹底一致就能夠利用索引完成查詢避免全表掃描。此處注意,查詢條件的順序和索引創建是的順序是一致的,後續的關於索引的最左前綴原則會進一步描述,此處記住是一致的就行 ####二丶(B+)-Tree索引基本實現 (B+)-Tree是一個數據結構,是一個平衡的多路查找二叉樹。Mysql innodb引擎中創建的索引默認就是基於(B+)-Tree實現的索引。
B-Tree和(B+)-Tree數據結構基本概念 關於B-Tree和(B+)-Tree數據結構具體特性參見該篇文章 ,本文借用上篇文章中的圖來剖析B-Tree是如何構建索引的。
上圖就是B+樹和B樹結構圖,很是清晰。B樹和B+樹之間有兩點最大的不一樣:
B+樹的葉子節點存儲了全部的數據,非葉子節點中存儲的是比較關鍵字。而B數全部的節點都會存儲數據。例如,在B+樹中查找數字26的過程是 p1->p3->26,最終在葉子節點裏找到了待查找數字26。在B樹中查找數字26,查找的順序是p2->26,在非葉子節點中查找到了數據就返回。
B+樹的葉子節點之間存在一個指針鏈接,B樹不存在指針鏈接。B+樹這種設計結構能帶來什麼好處呢? B+樹全部的數據都存儲在葉子節點,那麼順着葉子節點從左往右便可完成對數據的遍歷,極大了簡化了排序操做。這也是mysql設計索引是採用B+樹的緣由,不只僅能方便查找,並且有助於排序,在mysql的索引中葉子節點之間數雙向鏈表可正反遍歷,更加靈活
B+樹和Mysql索引之間關係 介紹關於B+樹數據結構的相關內容後,如何將其與索引聯繫在一塊兒呢?請看下圖
在一張數據表的整型id上創建一個索引,該索引對應的B+樹結構如上圖所示。在B+樹中經過主鍵之間的比較,最終在葉子節點將找到指向數據表中對應數據行的指針。經過訪問指針便可拿到需查找的數據,經過這種方式能夠避免對數據表全表掃描。極大的減小了檢索數據的時間
三丶關於Mysql常見術語的解疑
1. 聚族索引和非聚族索引
聚族索引和非聚族索引指的是存儲結構 Mysql中InnoDB存儲引擎是採用聚族索引的存儲方式,是在主鍵上創建的聚族索引 ,MyISAM則是非聚族索引的方式。下文引用《高性能Mysql第三版167頁的一張圖解釋下聚族索引和非聚族索引》 數據庫
聚族索引: 數據表和索引文件是存儲在一塊兒的,位於同一文件。如圖所示,以B+樹構建的索引,其葉子節點存儲了全部的行信息。數據表中的全部數據所有存儲在索引的葉子節點中
非聚族索引: 數據表和索引文件是分開存儲的,是兩個不一樣的文件。B+樹的葉子節點,並不存儲行信息,存儲的是數據行的物理地址。
InnoDB存儲引擎中非主鍵索引(二級索引)每一個葉子節點除了存儲索引字段外,額外存儲了主鍵列。經過二級索引檢索數據時,先檢索到主鍵列,最後經過主鍵列在聚族索引中檢索相應的數據行,這是一種二次檢索的過程。非聚族索引不存在這種過程
2. 索引覆蓋
理解索引的存儲結構後,理解索引的覆蓋就很是簡單了。若是select語句所查詢的字段所有都是索引列的話,稱爲索引覆蓋。數據結構
對於聚族索引而言,若是知足索引覆蓋,那麼不用經過主鍵訪問聚族索引。
對於非聚族索引而言,若是知足索引覆蓋,那麼不須要再次訪問數據表。 在知足索引覆蓋的條件下,select語句從索引文件從就能夠拿到所查詢的數據,而沒必要訪問數據行。
3. 最左前綴原則
最左前綴原則就是Mysql經過索引檢索數據時必須遵照的原則。最左前綴原則的內容規定以下,知足以下狀況,將使用索引查詢。 性能
全值匹配,select語句中的查詢條件(查詢字段和字段順序)和索引徹底對應。
匹配最左前綴,select語句中的查詢條件並未和索引徹底匹配。可是和索引最左側徹底匹配。好比index(col1,col2,col3),查詢條件(col1,col2)或者(col1)都成爲匹配索引的最左前綴。
匹配列前綴,這是匹配最左前綴長的特殊狀況。查詢條件是匹配索引第一列的開頭部分。好比 like col1 = aaa%。匹配索引第一列與aaa開頭的數據行。
匹配範圍,針對索引的第一列,使用了範圍查詢。好比, col1<A。
精確匹配某一個列,範圍匹配某一列。好比col1 =A and col2<B。精確匹配的列必須是索引的最左列。 ######4. 哈希索引 哈希索引不一樣於以B+樹爲存儲結構的索引。哈希以哈希爲存儲結構組織索引。
hash索引原理比較簡答,經過hash計算hashcode。hashcode = hash(col1,co2,..待索引列)。若是碰見hash衝突的話,能夠鏈地址方法解決衝突。hashcode對應存儲的value值是相關行的物理地址。哈希索引想比較於B+樹構建的索引,其有以下不一樣:
Hash索引檢索數據的速度比B+樹索引更快
Hash索引值只適用於全值匹配查詢,查詢條件和索引列必須徹底一致。B+樹所適應的最左前綴原則Hash索引並不適用
Hash索引只能知足精確匹配,好比查詢條件是==或者!=。並不能知足範圍查詢的場景。 ######5. 自適應哈希索引 自適應Hash索引是InnoDB存儲引擎添加的一種優化策略。InnoDB存儲引擎對那些查詢頻繁的索引條件,構建一個hash索引。下如有相同的查詢語句,則直接命中hash索引,而沒必要走B+樹索引,能提升檢索速度。自適應Hash索引是innoDB的一種優化策略,對用戶而言是透明的。
四丶索引的侷限性
有關索引侷限性的討論是一個比較有難度的話題,其不像原理分析那樣固定。其在不一樣的業務場景下會有不一樣的結論。本文論文幾種索引常見分析,並未涵蓋全部狀況 優化
什麼狀況須要創建索引?
當數據表較小時,維護索引的代價將超過索引加速查詢所帶來的好處。數據表較大時,索引可以極大加速查詢,適合建立索引。
對於那些,查詢多於增刪改的操做,創建索引是合適的。
在什麼列上創建索引
通常而言,選擇在選擇性比較高的列上創建索引。
選擇性 = 不重複的索引列/全部數據行數。選擇性越接近於1越好。
索引創建的順序。
受限於索引的最左前綴原則,索引創建的順序並不能是隨意的,應該和查詢場景相互印證。讓索引順序能知足最多的查詢場景
多列索引和多個單列索引
通常提供選擇創建多列索引,而不創建單例索引。多列索引能覆蓋單列索引的查詢條件。
是否針對不一樣的查詢條件,創建不一樣的索引
索引的創建是有代價的,包括索引存儲代價,數據增刪改的性能降低。對不一樣查詢條件創建索引,須要仔細考慮。 受限於做者水平,關於索引侷限性的討論,並不必定正確。在不一樣的場景,具備不一樣的選擇。