Mysql-索引的創建規則和使用場景以及組合索引的重點講解!(入木三分,簡潔明瞭)

前言:之前的項目中一直用Oracle數據庫,所以對Oracle的細節理解方面要遠勝於MySQL,這家公司用的MySQL,這幾天在做項目優化,看到之前的表中有的沒建索引,有的亂建索引(建了沒用到),所以我又重新梳理了一遍,正好對MySQL索引研究了研究,特寫下此文,供後來者參考。

這裏我不會講到索引的概念還有內部的詳細原理,我會根據場景講解什麼時候要建索引,怎麼建索引,怎麼用索引,索引在什麼查詢語句中會失效等問題。

正文:

   1.    建立索引的目的是什麼?就是爲了快快快!

   2. 爲什麼使用索引查詢會變快?廣義來講:就是用空間來換取時間,索引就是內存塊。

MySql索引類型:

普通索引INDEX:加速查找(需自己創建)

唯一索引:
    -主鍵索引PRIMARY KEY:加速查找+約束(不爲空、不能重複, 在創建表的時候自動生成的)
    -唯一索引UNIQUE:加速查找+約束(不能重複,需自己創建)

聯合索引(組合索引):
    -PRIMARY KEY(id,name):聯合主鍵索引
    -UNIQUE(id,name):聯合唯一索引
    -INDEX(id,name):聯合普通索引

#我們可以在創建上述索引的時候,爲其指定索引類型,分兩類
hash類型的索引:查詢單條快,範圍查詢慢
btree類型的索引:b+樹,層數越多,數據量指數級增長(我們就用它,因爲innodb默認支持它)

#不同的存儲引擎支持的索引類型也不一樣
InnoDB 支持事務,支持行級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
Memory 不支持事務,支持表級別鎖定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
NDB 支持事務,支持行級別鎖定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
Archive 不支持事務,支持表級別鎖定,不支持 B-tree、Hash、Full-text 等索引

------------------------------------------------------------------------------------------------

問題一:什麼表都需要建立索引嗎?

創建表的目的是什麼?是實現業務!舉個例子:如果一張表中只是存儲了一個公司內部各位董事的個人信息,這家公司就算再大,董事也不會太多,所以沒必要創建索引,因爲數據量太少的話,及時創建了索引,Mysql也會進行全表掃描(數據庫很智能,它會選擇它認爲最快的執行計劃);

如果一張表是訂單業務表,那就必須要創建索引。

問題二:創建什麼樣的索引最合適?

還是歸結於業務。比如一個電商內部管理系統,創建的訂單表該怎麼加索引?開發人員至少要想到兩點:

1.系統使用者的查詢習慣,比如使用者的查詢習慣是城市city,習慣查詢某個城市的訂單信息,這時候 city這個字段可以作爲單索引。

比如使用者習慣查詢 某個城市在某個時間單的訂單信息,那麼最好的方式是創建 組合索引:idx_city_time(city,time);

有些人會說分別創建兩個單獨的索引(idx_city 和  idx_time)不行嗎?

答:針對上述場景是不行的,因爲在MySQL執行的時候,一張表只會有一個索引生效

解析:

兩個單字段索引:

select * from order where city='BJ' and time<'2020-12-12';兩個單獨索引的話,idx_city會生效,idx_time不會生效。

我講一下這個SQL的where後面條件大概查詢過程:

(1)MySQL where條件是從左到右執行的,先執行city='BJ',city這個字段有索引,所以BJ這個值是直接從索引中查詢,而不是中表中搜索的(我們前面說了,索引是單獨的內存區間),比如符合這個條件的有5條數據,索引中就會有5條,然後再根據這5條索引中的數據找到表中的5條數據,而不是直接去表中全表搜索符合條件的數據。

假如:select city from order where city='BJ'; 因爲city這個字段的數據在索引中,直接獲取到了,就無須通過索引再到表中獲取。

(2)通過idx_city找到的表中 5條數據,然後再從這些數據中全表查詢符合time<'2020-12-12' 條件的數據。即使time有索引也不會走。

一個組合索引:

如果是一個組合索引idx_city_time(city,time),同樣的SQL,select * from order where city='BJ' and time<'2020-12-12';

where後面的條件 city 和time,都會先走索引,由於搜索結果是 * ,所以再通過索引找到表中對應的數據。

 

這裏我重點講一下組合索引!!!

最左前綴匹配原則

在mysql建立聯合索引時會遵循最左前綴匹配的原則,即最左優先,在檢索數據時從聯合索引的最左邊開始匹配,示例:
對列col1、列col2和列col3建一個聯合索引

?

1

KEY test_col1_col2_col3 on test(col1,col2,col3);

聯合索引 test_col1_col2_col3 實際建立了(col1)、(col1,col2)、(col,col2,col3)三個索引。

?

1

SELECT * FROM test WHERE col1=“1” AND clo2=“2” AND clo4=“4”

上面這個查詢語句執行時會依照最左前綴匹配原則,檢索時會使用索引(col1,col2)進行數據匹配。

注意

索引的字段可以是任意順序的,如:

?

1

2

SELECT * FROM test WHERE col1=“1” AND clo2=“2”

SELECT * FROM test WHERE col2=“2” AND clo1=“1”

這兩個查詢語句都會用到索引(col1,col2),mysql創建聯合索引的規則是首先會對聯合合索引的最左邊的,也就是第一個字段col1的數據進行排序,在第一個字段的排序基礎上,然後再對後面第二個字段col2進行排序。其實就相當於實現了類似 order by col1 col2這樣一種排序規則。

有人會疑惑第二個查詢語句不符合最左前綴匹配:首先可以肯定是兩個查詢語句都保函索引(col1,col2)中的col1、col2兩個字段,只是順序不一樣,查詢條件一樣,最後所查詢的結果肯定是一樣的。既然結果是一樣的,到底以何種順序的查詢方式最好呢?此時我們可以藉助mysql查詢優化器explain,explain會糾正sql語句該以什麼樣的順序執行效率最高,最後才生成真正的執行計劃。

爲什麼要使用聯合索引

減少開銷。建一個聯合索引(col1,col2,col3),實際相當於建了(col1),(col1,col2),(col1,col2,col3)三個索引。每多一個索引,都會增加寫操作的開銷和磁盤空間的開銷。對於大量數據的表,使用聯合索引會大大的減少開銷!

覆蓋索引。對聯合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那麼MySQL可以直接通過遍歷索引取得數據,而無需回表,這減少了很多的隨機io操作。減少io操作,特別的隨機io其實是dba主要的優化策略。所以,在真正的實際應用中,覆蓋索引是主要的提升性能的優化手段之一。

效率高。索引列越多,通過索引篩選出的數據越少。有1000W條數據的表,有如下sql:select from table where col1=1 and col2=2 and col3=3,假設假設每個條件可以篩選出10%的數據,如果只有單值索引,那麼通過該索引能篩選出1000W10%=100w條數據,然後再回表從100w條數據中找到符合col2=2 and col3= 3的數據,然後再排序,再分頁;如果是聯合索引,通過索引篩選出1000w10% 10% *10%=1w,效率提升可想而知!

 

我下一章會講一下MySQL 查詢語句的執行順序,希望小夥伴們留言!

 

江湖險惡,我從來都不輕易留下我的名字~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章