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優化來縮小候選集范圍
(7)使用索引的注意事項
使用索引時,有以下一些技巧和注意事項:
◆索引不會包含有NULL值的列
只要列中包含有NULL值都將不會被包含在索引中,復合索引中只要有一列含有 NULL值,那么這一列對於此復合索引就是無效的。所以我們在數據庫設計時不要讓字段的默認值為NULL。
◆使用短索引
對串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的列,如果在前10個或20個字符內,多數值是惟一的,那么就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。
◆索引列排序
MySQL查詢只使用一個索引,因此如果 where子句中已經使用了索引的話,那么order by中的列是不會使用索引的。因此數據庫默認排序可以符合要求的情況下不要使用排序操作;盡量不要包含多個列的排序,如果需要最好給這些列創建復合索引。
◆like語句操作
一般情況下不鼓勵使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引而like “aaa%”可以使用索引。
◆不要在列上進行運算
select * from users where YEAR(adddate)<2007;
將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成
select * from users where adddate<‘2007-01-01’;
◆不使用NOT IN和<>操作
引用: http://zhidao.baidu.com/link?url=xF1BrmM9CNSE_ptqmRcEZQgTHIw5UK7WbMI_iAOMWzYS8MdNYbVMrpv820wzn6nxlkpyx2JAH_OXmAqFbfR32K
