索引的分類
索引分爲B-Tree索引、哈希索引、空間索引、全文索引、其他等索引。
在 MySQL 中,最常用的是 B-Tree 索引(也就是我們常說的B+樹索引,這裏B-Tree索引只是一個分類)
索引的優點
-
索引大大減少了服務器需要掃描的數據量
-
索引可以幫助服務器避免排序和臨時表
-
索引可以將隨機I/O變成順序I/O
創建高性能索引
下面根據不同的情況來說明,如何創建合適並且高性能的索引來提高索引效率。
- 獨立的列
如果查詢中的列不是獨立的,則 MySQL不會使用索引。
所謂獨立的列指的是,查詢中的列不能是表達式的一部分,要是獨立的,舉例如下
select * from t_user where id + 1 = 9;
在上面的查詢語句,查詢中的列 id
不是獨立的,而是表達式 id + 1
的一部分,因此索引不會生效
關於索引失效的各種情況,詳情參考 MySQL索引失效總結
- 前綴索引
有時候需要很長的字符列,這會讓索引變得大且慢。
我們可以索引開始的部分字符,這樣可以大大節約索引空間,從而提高索引效率。
當然,選擇的部分字符不合適會導致過濾效果很差,所以一定要選擇區分度較高的前綴建立索引。
創建前綴索引腳本如下:
alter table t_user add key (address(10));
該腳本表示以地址的前10個字符創建索引。
- 多列索引
很多人對多列索引理解不夠,爲多個列創建獨立的索引,或者按照錯誤的順序創建多列索引。
在多個列上建立獨立的索引,一般情況下並不能提高MySQL的性能,正確的做法是,根據 where 條件的情況,在多個列上建立組合索引。
使用多列索引,查詢條件必須滿足最左前綴原則,也就是說,where 條件的順序與組合索引字段的順序要保持一致。
比如我們在字段1和字段2上建立組合索引,而查詢條件只有字段2,此時並不會走索引進行查詢。
- 覆蓋索引
索引確實是一種查找數據的高效方式,但是 MySQL 也可以直接使用索引獲取列的數據,這樣就不再需要讀取數據行了。
如果一個索引包含所有需要查詢的字段的值,我們就稱之爲 覆蓋索引
。
比如我們要查詢用戶的角色,一個用戶會有多種角色,通常我們在 用戶ID和角色ID 建立一個索引,這樣我們查詢用戶的角色ID列表的時候,直接可以通過索引返回,不需要再回表。
- 利用索引進行排序
當索引的順序和 ORDER BY 子句的順序完全一致,並且所有列的排序方向都一樣時,MySQL 能夠使用索引來對結果做排序。
比如,我們經常需要根據創建時間進行排序,那麼在創建時間字段上建立一個索引,在進行排序查詢的時候就會高效很多。
當 ORDER BY 子句不滿足索引的最左前綴的要求時,就無法利用索引進行排序。
當然,特殊情況,也就是說,假如 ORDER BY 子句是從索引的第二個字段開始,但是索引的第一個字段被至指定爲常數,也可以用於查詢排序。
- 創建區分度高的索引
比如,用戶性別,我們知道性別取值一般是 男和女
,也就兩個值,重複率很高,如果在性別字段上創建索引,那麼索引的效率就很低。
再比如,用戶身份證號,每個人的身份證號都是不同的,在身份證號字段上建立索引,區分度就非常,根據身份證號索引的效率就很高。
總結
在選擇索引和編寫利用這些索引的查詢時,需要根據具體業務情況來定,沒有萬能的方法。不過一般我們需要記住下面幾個原則:
-
單行訪問是很慢的。如果服務器從存儲中讀取一個數據塊只是爲了獲取某一行數據,那麼就浪費了很多工作。最好讀取的數據塊中包含儘可能多的數據行。
-
按順序訪問範圍數據是很快的。原因是:第一,順序I/O不需要多次磁盤尋道,比隨機I/O要快得多;第二,如果服務器能按順序讀取數據,那麼就不需要額外進行排序操作了。
-
索引覆蓋查詢時很快的。如果一個索引包含了查詢需要的所有列,那麼存儲引擎就不需要再回表查找數據行了。