本文是針對Mysql索引原理剖析的入門級文章,主要圍繞以下四個話題展開對索引相關原理的描述。
- 一丶索引基本概念
- 二丶(B+)-Tree索引基本實現
- 三丶關于Mysql索引常見術語解疑(聚族索引逢净,非聚族索引巨柒,最左前綴原則, 索引覆蓋,哈希索引,自適應哈希索引)
- 四丶索引局限性
一丶索引基本概念
對照著生活中的概念嘱么,數據庫索引的概念理解起來比較容易。數據庫的索引相當于書籍的目錄柒傻。
-
書籍目錄:
查閱書籍內容時可對照著目錄孝赫,直接定位到想查閱內容的具體頁數,避免逐頁翻書的工作量 -
數據庫索引:
某條查詢sql語句可以對照數據表中的索引红符,直接定位到符合查詢條件的數據行的物理地址青柄,避免對數據表進行全表掃描的工作。
上述概念關于索引的概念很簡單预侯,但是包含了很多的信息量致开。進一步挖掘如下:- 索引是建立數據表上的,每張數據表都可以有自己的索引萎馅。并且數據表中的索引可以有多個双戳,但是不能設置重復的索引。
- 索引更具體一點來說糜芳,其是建立在數據表的相關列上, 畢竟只有索引建立在列上才能和查詢條件相關聯嘛飒货。若索引在一個列上建立稱為單一索引,若索引在多個列上建立成為復合索引峭竣。在表table1中的col1塘辅,col2,col3列上建立名為indx1的索引的sql語句如下:
create index idx1 on table1(col1,col2,col3)
這里需要特別注意皆撩,索引和建立索引時的數據列順序有關扣墩,比如在col3,col2毅访,col1這三個列上建立名為idx2的索引和上述idx1索引是不同的索引沮榜。這是一個非常重要的概念 - 索引是一個獨立于數據表的結構,就像書籍一樣喻粹,目錄和正文分屬于不同的部分蟆融。數據表的內容發(fā)生了改變了,那么索引的結構也會發(fā)生相應調整守呜,簡而言之型酥,索引的更新和數據表內容的更新保持一致。
該條具體一點就是查乒,在對建立了索引的相關列進行增刪改操作時弥喉,會附加維護索引結構的相關操作。未建立索引的列則不需要考慮這個性能消耗玛迄。 - 索引提高查詢的性能由境,索引通過避免全表掃描,減少掃描行的數量來提高查詢的性能。
- 對于一條簡單的查詢來說虏杰,是如何使用索引查詢的呢讥蟆?
select * from table1 where col1 = A and col2 = B and col3 = C 這條查詢就利用idx1這個索引。目前來看纺阔,非常簡單查詢條件和索引列完全一致就可以利用索引完成查詢避免全表掃描瘸彤。此處注意,查詢條件的順序和索引建立是的順序是一致的笛钝,后續(xù)的關于索引的最左前綴原則會進一步描述质况,此處記住是一致的就行
二丶(B+)-Tree索引基本實現
(B+)-Tree是一個數據結構,是一個平衡的多路查找二叉樹玻靡。Mysql innodb引擎中建立的索引默認就是基于(B+)-Tree實現的索引结榄。
- B-Tree和(B+)-Tree數據結構基本概念
關于B-Tree和(B+)-Tree數據結構具體特性參見該篇文章,本文借用上篇文章中的圖來剖析B-Tree是如何構建索引的啃奴。
上圖就是B+樹和B樹結構圖潭陪,非常清晰。B樹和B+樹之間有兩點最大的不同:
- B+樹的葉子節(jié)點存儲了所有的數據最蕾,非葉子節(jié)點中存儲的是比較關鍵字依溯。而B數所有的節(jié)點都會存儲數據。例如瘟则,在B+樹中查找數字26的過程是 p1->p3->26,最終在葉子節(jié)點里找到了待查找數字26黎炉。在B樹中查找數字26,查找的順序是p2->26,在非葉子節(jié)點中查找到了數據就返回醋拧。
- B+樹的葉子節(jié)點之間存在一個指針連接慷嗜,B樹不存在指針連接。B+樹這種設計結構能帶來什么好處呢丹壕?
B+樹所有的數據都存儲在葉子節(jié)點庆械,那么順著葉子節(jié)點從左往右即可完成對數據的遍歷,極大了簡化了排序操作菌赖。這也是mysql設計索引是采用B+樹的原因缭乘,不僅僅能方便查找,而且有助于排序琉用,在mysql的索引中葉子節(jié)點之間數雙向鏈表可正反遍歷堕绩,更加靈活
-
B+樹和Mysql索引之間關系
介紹關于B+樹數據結構的相關內容后,如何將其與索引聯系在一起呢邑时?請看下圖
在一張數據表的整型id上建立一個索引奴紧,該索引對應的B+樹結構如上圖所示。在B+樹中通過主鍵之間的比較晶丘,最終在葉子節(jié)點將找到指向數據表中對應數據行的指針黍氮。通過訪問指針即可拿到需查找的數據,通過這種方式可以避免對數據表全表掃描。極大的減少了檢索數據的時間
三丶關于Mysql常見術語的解疑
1. 聚族索引和非聚族索引
聚族索引和非聚族索引指的是存儲結構
Mysql中InnoDB存儲引擎是采用聚族索引的存儲方式沫浆,是在主鍵上建立的聚族索引觉壶,MyISAM則是非聚族索引的方式。下文引用《高性能Mysql第三版167頁的一張圖解釋下聚族索引和非聚族索引》
聚族索引:數據表和索引文件是存儲在一起的件缸,位于同一文件。如圖所示叔遂,以B+樹構建的索引他炊,其葉子節(jié)點存儲了所有的行信息。數據表中的所有數據全部存儲在索引的葉子節(jié)點中
非聚族索引:數據表和索引文件是分開存儲的已艰,是兩個不同的文件痊末。B+樹的葉子節(jié)點,并不存儲行信息哩掺,存儲的是數據行的物理地址凿叠。
InnoDB存儲引擎中非主鍵索引(二級索引)每個葉子節(jié)點除了存儲索引字段外,額外存儲了主鍵列嚼吞。通過二級索引檢索數據時盒件,先檢索到主鍵列,最后通過主鍵列在聚族索引中檢索相應的數據行舱禽,這是一種二次檢索的過程炒刁。非聚族索引不存在這種過程
2. 索引覆蓋
理解索引的存儲結構后,理解索引的覆蓋就非常簡單了誊稚。如果select語句所查詢的字段全部都是索引列的話翔始,稱為索引覆蓋。
- 對于聚族索引而言里伯,如果滿足索引覆蓋城瞎,那么不用通過主鍵訪問聚族索引。
- 對于非聚族索引而言疾瓮,如果滿足索引覆蓋脖镀,那么不需要再次訪問數據表。
在滿足索引覆蓋的條件下爷贫,select語句從索引文件從就可以拿到所查詢的數據认然,而不必訪問數據行。
3. 最左前綴原則
最左前綴原則就是Mysql通過索引檢索數據時必須遵守的原則漫萄。最左前綴原則的內容規(guī)定如下卷员,滿足如下情況,將使用索引查詢腾务。
- 全值匹配毕骡,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存儲引擎添加的一種優(yōu)化策略堰怨。InnoDB存儲引擎對那些查詢頻繁的索引條件芥玉,構建一個hash索引。下若有相同的查詢語句备图,則直接命中hash索引灿巧,而不必走B+樹索引赶袄,能提高檢索速度。自適應Hash索引是innoDB的一種優(yōu)化策略抠藕,對用戶而言是透明的饿肺。
四丶索引的局限性
有關索引局限性的討論是一個比較有難度的話題,其不像原理分析那樣固定盾似。其在不同的業(yè)務場景下會有不同的結論敬辣。本文論文幾種索引常見分析,并未涵蓋所有情況
- 什么情況需要建立索引零院?
- 當數據表較小時购岗,維護索引的代價將超過索引加速查詢所帶來的好處。數據表較大時门粪,索引能夠極大加速查詢,適合創(chuàng)建索引烹困。
- 對于那些玄妈,查詢多于增刪改的操作,建立索引是合適的髓梅。
- 在什么列上建立索引
- 一般而言拟蜻,選擇在選擇性比較高的列上建立索引。
- 選擇性 = 不重復的索引列/所有數據行數枯饿。選擇性越接近于1越好酝锅。
- 索引建立的順序。
- 受限于索引的最左前綴原則奢方,索引建立的順序并不能是隨意的搔扁,應該和查詢場景相互印證。讓索引順序能滿足最多的查詢場景
- 多列索引和多個單列索引
- 一般提供選擇建立多列索引蟋字,而不建立單例索引稿蹲。多列索引能覆蓋單列索引的查詢條件。
- 是否針對不同的查詢條件鹊奖,建立不同的索引
- 索引的建立是有代價的苛聘,包括索引存儲代價,數據增刪改的性能下降忠聚。對不同查詢條件建立索引设哗,需要仔細考慮。
受限于作者水平两蟀,關于索引局限性的討論网梢,并不一定正確。在不同的場景垫竞,具有不同的選擇澎粟。