《跬步千里系列》高性能MySql之索引究竟是個啥

首發:www.leroyling.com/archives/my…mysql

生活中,若是你想要快速的在一本書中找到某個你感興趣的內容,通常來說是會先看書的「索引」部分,也就是書的目錄,找到對應的頁碼以後,再翻去看你感興趣的具體內容。sql

在MySQL中,存儲引擎也用的相似的方法使用索引,即如今索引中找到對應的值,而後根據匹配到的索引的記錄找到對應的數據行。索引能夠包含一個或多個列的值,若是索引含有多個列,那麼如何放置列的順序也是至關重要的,由於在MySQL中只能高效的使用索引的最左前綴列。因此在MySQL中建立一個包含兩個列的索引,和單首創建兩個各自只包含一個列的索引效果也會大不同。函數

索引的類型

1.1 B-Tree索引

通常來講,當咱們說到索引的時候,若是沒有特別的指明類型,那麼多半來講,默認說的就是B-Tree索引了(不一樣的存儲引擎中,可能使用了不一樣的存儲結構,如InnoDB引擎中使用的是B+Tree)。性能

使用B-Tree索引,意味着所存儲的值是按照順序存儲的。使用索引之因此能加快訪問數據的速度,是由於存儲引擎不在須要對數據進行全表掃描了,而是從索引的根節點開始搜索,經過比較節點頁的值和實際要查找的值,從而找到合適的指針進入下層的子節點進行查找。 以一張簡單的表爲例:優化

CREATE TABLE ORDER(
order_id varchar(32) not null,
product_code varchar(20) not null,
order_time datetime not null,
order_price decimal(10,2) not null default 0,
address varchar(100) not null
key(order_id,product_code,order_time)
)
複製代碼

對於上面表中的每一條數據,索引中都包含了 order_id, product_code, order_time這三列的值。對於多個列的值進行排序的時候,排序規則是根據create語句中定義索引時使用的列順序來進行的,以上表爲例,即排序的順序爲order_id, product_code, order_time。ui

可以命中索引的查詢方式

  • 全值匹配 指的是查詢語句中where條件的列和索引中的全部列都匹配,好比前面表中的
select * from order where order_id ='o001' and product_code='p001' and order_time='2019-12-05';
複製代碼
  • 最左前綴匹配 指的是查詢條件命中了索引從左到右的部分順序
select * from order where order_id='o001';

select * from order where order_id='o001' and product_code='p001'
複製代碼
  • 列前綴匹配 只匹配到了索引中列的開頭部分
select * from order where order_id like 'o001%';

select * from order where order_id ='o0001' and product_code like 'p001%';
複製代碼
  • 列範圍值匹配
select * from order where order_id >='o001';

select * from order where order_id = 'o001' and product_code >'p001';

select * from order where order_id = 'o001' and product_code ='p001' and order_time >'2019-12-01';
複製代碼
  • 只訪問索引的查詢搜索引擎

    即查詢只須要訪問索引而無需訪問數據行,此時這種查詢進化爲一種名爲「覆蓋索引」查詢。所謂的「覆蓋索引」指的是若是一個索引包含(或者說覆蓋)全部須要查詢返回的字段的值,那麼這個索引就稱之爲「覆蓋索引」。此時查詢結果可使用索引來直接獲取列的數據,再也不須要回表讀取數據行。spa

1.2 哈希索引

哈希索引是基於哈希表實現的,只能精準匹配索引的全部列的查詢時纔會生效。在Mysql中,只有Memory引擎顯式的支持哈希索引,這也是Memory引擎的默認索引類型,同時Memory引擎也支持B-Tree索引。指針

由於哈希索引自身只須要存儲對應的哈希值,因此索引的結構會十分的緊湊,這也讓哈希索引的查找速度變的很是快。可是哈希索引在使用時也有它的一些限制:code

  • 哈希索引只包含哈希值和行指針,不存儲字段值,所以不能使用索引中的值來避免讀取行數據。不過因爲訪問內容中的行數據的速度很快,因此大部分的狀況下這一點對性能的影響並不明顯。
  • 由於哈希索引的數據並非按照索引值的順序存儲的,因此哈希索引沒法用於排序。
  • 由於哈希索引時全部列的哈希,由於不支持部分索引列的匹配查找。好比對於Index(key1,key2)的哈希索引而言,若是查詢條件中只有key1,那麼查詢的時候將不會使用索引查詢。
  • 哈希索引只支持等值比較查詢,包括=、in()、<=>,不支持熱呢範圍查詢,好比 where order_time >'2019-12-01'。
  • 訪問哈希索引的數據速度很是快,除非有不少的哈希衝突(不一樣的索引列值卻有着相同的哈希值)。當出現哈希衝突的時候,存儲引擎必需要遍歷鏈表中的全部行指針,對數據進行逐行比較,直到找到全部符合條件的數據。
  • 若是哈希衝突不少的話,一些索引的維護操做代價會變得很高昂。好比刪除表中的一條數據時,存儲引擎須要遍歷對應哈希表的鏈表中的每一行,找到並刪除對應行的引用,此時,哈希衝突越多,代價越高昂。

在InnoDB引擎中有個特殊的功能叫「自適應哈希索引(adaptive hash index)」。說的是當InnoDB注意到某些索引值被應用的很是頻繁的時候,它會在內存中基於B-Tree索引之上再建一個哈希索引,這樣會讓B-Tree索引也具備一部分的哈希索引的優勢,好比快速的哈希查找。不過這是一個徹底自動的引擎內部的行爲,用戶沒法控制或配置。

1.3 空間數據索引(R-Tree)

MyISAM表支持空間索引,能夠用做地理數據存儲。這類索引無需前綴查詢,空間索引會從全部維度來索引數據。查詢時,能夠有效的使用任意維度來組合查詢。可是必需要使用MYySQL的GIS相關函數來維護數據。MySQL的GIS支持的並不完善,由於大部分人不會去使用這個特性。

1.4 全文索引

全文索引時一種特殊類型的額索引,它查找的是文本中的關鍵詞,而不是直接比較索引中的值。全文搜索和其餘幾類索引的匹配方式徹底不同。全文索引更相似於搜索引擎作的事情,而不是簡單的where查詢條件匹配。

在相同的列上同時建立全文索引和基於值的B-Tree索引不會有衝突。

索引優化策略

  • 創建索引的列不要參與數學計算或者函數計算。
  • 須要索引很長字符的列時,經過驗證索引的選擇性,對該列進行前綴索引。
  • 因爲MySQL原生不支持反向索引,當遇到須要進行後綴數據索引查詢時,能夠經過將字符反轉後存儲,並基於此創建前綴索引。經過觸發器來維護此類索引(自定義索引)。
  • 當有多個列字段須要索引時,優先考慮聯合索引,而不是將每一個列單獨的建立索引
  • 多列索引中須要正確選擇索引列的順序,以便更好地知足排序和分組的須要。
相關文章
相關標籤/搜索