mysql> alter table SUser add index index1(email);
或
mysql> alter table SUser add index index2(email(6));
我們知道,如果選擇給字符串加索引,那么索引的區(qū)分度會影響查詢效率,如果同一個索引值有N個相同的前綴,就會多次回表查詢,影響效率,所以怎么選擇索引長度呢?
一、如何選擇索引長度?
首先,你可以使用下面這個語句,算出這個列上有多少個不同的值:
mysql> select count(distinct email) as L from SUser;
然后,依次選取不同長度的前綴來看這個值,比如我們要看一下 4~7 個字節(jié)的前綴索引,可以用這個語句
mysql> select
count(distinct left(email,4))as L4,
count(distinct left(email,5))as L5,
count(distinct left(email,6))as L6,
count(distinct left(email,7))as L7,
from SUser;
當(dāng)然,使用前綴索引很可能會損失區(qū)分度,所以你需要預(yù)先設(shè)定一個可以接受的損失比例,比如 5%。然后,在返回的 L4~L7 中,找出不小于 L * 95% 的值,假設(shè)這里 L6、L7 都滿足,你就可以選擇前綴長度為 6。
二、用前綴索引就不能用覆蓋索引優(yōu)化了
因為系統(tǒng)并不確定前綴索引的定義是否截斷了完整信息,所以前綴索引就會回表。
三、其它方式加索引
1.倒序存儲
例子:比如你要創(chuàng)建以身份證為索引的查詢,因為身份證號在同一區(qū)縣的前幾位都是相同的,所以截取前幾位身份證為索引的區(qū)分度并不高。
mysql> select field_list from t where id_card = reverse('input_id_card_string');
2.使用hash字段
在表中新增一個字段,用于存儲hash( crc32() 這個函數(shù))身份證號后的值。crc32有四個字節(jié)。
mysql> alter table t add id_card_crc int unsigned, add index(id_card_crc);
因為可能存在hash沖突,所以要判斷身份證的全部值。
mysql> select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'
3.使用倒序前綴和hash的區(qū)別
相同點:因為都對原主鍵進(jìn)行處理,只適合等值查詢,不適合范圍查詢。
不同點:
(1)占用額外空間看,倒序不用新增字段,但是前綴長度可能超過hash的crc32函數(shù)的4個字節(jié),總體上差不多。
(2)cpu占用來看,倒序使用的reverse函數(shù)比crc32函數(shù)占用要少。
(3)查詢效率看,hash使用的crc32函數(shù)發(fā)生hash沖突的概率比前綴的區(qū)分度小發(fā)生回表查詢的概率要小。
三、思考題
如果你在維護(hù)一個學(xué)校的學(xué)生信息數(shù)據(jù)庫,學(xué)生登錄名的統(tǒng)一格式是”學(xué)號 @gmail.com", 而學(xué)號的規(guī)則是:十五位的數(shù)字,其中前三位是所在城市編號、第四到第六位是學(xué)校編號、第七位到第十位是入學(xué)年份、最后五位是順序編號。
系統(tǒng)登錄的時候都需要學(xué)生輸入登錄名和密碼,驗證正確后才能繼續(xù)使用系統(tǒng)。就只考慮登錄驗證這個行為的話,你會怎么設(shè)計這個登錄名的索引呢?