MySQL單列索引和組合索引的區別

尼古拉斯--趙四發表於2017-05-27

MySQL單列索引是我們使用MySQL資料庫中經常會見到的,MySQL單列索引和組合索引的區別可能有很多人還不是十分的瞭解,下面就為您分析兩者的主要區別,供您參考學習。

  為了形象地對比兩者,再建一個表:

CREATE TABLE myIndex (

 i_testID INT NOT NULL AUTO_INCREMENT, 

vc_Name VARCHAR(50) NOT NULL, 

vc_City VARCHAR(50) NOT NULL, 

i_Age INT NOT NULL, 

i_SchoolID INT NOT NULL, 

PRIMARY KEY (i_testID) 

);

  在這 10000 條記錄裡面 7 上 8 下地分佈了 5 條 vc_Name="erquan" 的記錄,只不過 city,age,school 的組合各不相同。

  來看這條T-SQL:

SELECT i_testID FROM myIndex WHERE vc_Name='erquan' AND vc_City='鄭州' AND i_Age=25;

  首先考慮建MySQL單列索引:

  在vc_Name列上建立了索引。執行 T-SQL 時,MYSQL 很快將目標鎖定在了vc_Name=erquan 的 5 條記錄上,取出來放到一中間結果集。在這個結果集裡,先排除掉 vc_City 不等於"鄭州"的記錄,再排除 i_Age 不等於 25 的記錄,最後篩選出唯一的符合條件的記錄。

  雖然在 vc_Name 上建立了索引,查詢時MYSQL不用掃描整張表,效率有所提高,但離我們的要求還有一定的距離。同樣的,在 vc_City 和 i_Age 分別建立的MySQL單列索引的效率相似。

為了進一步榨取 MySQL 的效率,就要考慮建立組合索引。就是將 vc_Name,vc_City,i_Age 建到一個索引裡:

ALTER TABLE myIndex ADD INDEX name_city_age (vc_Name(10),vc_City,i_Age);

  建表時,vc_Name 長度為 50,這裡為什麼用 10 呢?因為一般情況下名字的長度不會超過 10,這樣會加速索引查詢速度,還會減少索引檔案的大小,提高 INSERT 的更新速度。

  執行 T-SQL 時,MySQL 無須掃描任何記錄就到找到唯一的記錄。

  肯定有人要問了,如果分別在 vc_Name,vc_City,i_Age 上建立單列索引,讓該表有 3 個單列索引,查詢時和上述的組合索引效率一樣嗎?大不一樣,遠遠低於我們的組合索引雖然此時有了三個索引,但 MySQL 只能用到其中的那個它認為似乎是最有效率的單列索引。

  建立這樣的組合索引,其實是相當於分別建立了

(vc_Name,vc_City,i_Age)   ( vc_Name,vc_City ) ( vc_Name)

  這樣的三個組合索引!為什麼沒有 vc_City,i_Age 等這樣的組合索引呢?這是因為 mysql 組合索引“最左字首”的結果。簡單的理解就是只從最左面的開始組合。並不是只要包含這三列的查詢都會用到該組合索引,下面的幾個 T-SQL 會用到:

SELECT * FROM myIndex WHREE vc_Name="erquan" AND vc_City="鄭州"

SELECT * FROM myIndex WHREE vc_Name="erquan"

  而下面幾個則不會用到:

SELECT * FROM myIndex WHREE i_Age=20 AND vc_City="鄭州" 
SELECT * FROM myIndex WHREE vc_City="鄭州"


1. 為什麼使用索引

在無索引的情況下,MySQL會掃描整張表來查詢符合sql條件的記錄,其時間開銷與表中資料量呈正相關。對關係型資料表中的某些欄位建索引可以極大提高查詢速度(當然,不同欄位是否selective會導致這些欄位建立的索引對查詢速度的提升幅度不同,而且索引也並非越多越好,因為寫入或刪除時需要更新索引資訊)。

對於MySQL的Innodb儲存引擎來說,大部分型別的index均以B-Tree資料結構的變種B+Tree來儲存(MEMORY型別的表還支援hash型別的索引)。B-Tree是資料庫或檔案系統中常用的一種資料結構,它是一種N叉平衡樹,這種樹結構保證了同層節點儲存的key有序,對於某個節點來說,其左子樹儲存的所有key均小於該節點儲存的key,其右子樹儲存的所有key均大於該節點儲存的key。此外,在工程實現上,還結合作業系統的區域性性原理做了很多優化,總之,b-tree的各種特性或優化技巧能保證:1) 查詢磁碟記錄時,讀盤次數最少;2) 任何insert和delete操作對樹結構的影響均很小;3) 樹本身的rebalance操作很高效。

2. MySQL使用索引的場景

MySQL在以下操作場景下會使用索引:
1) 快速查詢符合where條件的記錄
2) 快速確定候選集。若where條件使用了多個索引欄位,則MySQL會優先使用能使候選記錄集規模最小的那個索引,以便儘快淘汰不符合條件的記錄。
3) 如果表中存在幾個欄位構成的聯合索引,則查詢記錄時,這個聯合索引的最左字首匹配欄位也會被自動作為索引來加速查詢。
例如,若為某表建立了3個欄位(c1, c2, c3)構成的聯合索引,則(c1), (c1, c2), (c1, c2, c3)均會作為索引,(c2, c3)就不會被作為索引,而(c1, c3)其實只利用到c1索引。
4) 多表做join操作時會使用索引(如果參與join的欄位在這些表中均建立了索引的話)
5) 若某欄位已建立索引,求該欄位的min()或max()時,MySQL會使用索引
6) 對建立了索引的欄位做sort或group操作時,MySQL會使用索引


  3. 哪些SQL語句會真正利用索引
從MySQL官網文件"Comparison of B-Tree and Hash Indexes"可知,下面這些型別的SQL可能會真正用到索引:

1) B-Tree可被用於sql中對列做比較的表示式,如=, >, >=, <, <=及between操作

2) 若like語句的條件是不以萬用字元開頭的常量串,MySQL也會使用索引
比如,SELECT * FROM tbl_name WHERE key_col LIKE 'Patrick%'或SELECT * FROM tbl_name WHERE key_col LIKE 'Pat%_ck%'可以利用索引,而SELECT * FROM tbl_name WHERE key_col LIKE '%Patrick%'(以萬用字元開頭)和SELECT * FROM tbl_name WHERE key_col LIKE other_col(like條件不是常量串)無法利用索引。
對於形如LIKE '%string%'的sql語句,若萬用字元後面的string長度大於3,則MySQL會利用Turbo Boyer-Moore algorithm演算法進行查詢。

3) 若已對名為col_name的列建了索引,則形如"col_name is null"的SQL會用到索引

4) 對於聯合索引,sql條件中的最左字首匹配欄位會用到索引,示例請參考本文第2節第3條對聯合索引的說明

5) 若sql語句中的where條件不只1個條件,則MySQL會進行Index Merge優化來縮小候選集範圍









相關文章