本文已收錄GitHub,更有互聯網大廠面試真題,面試攻略,高效學習資料等mysql
假設創建一個支持郵箱登陸的用戶表,對於郵件字段來講,能夠有如下幾種創建索引的方式:git
①. 直接對整個字符串創建索引github
alter table SUser add index index1(email);
②. 對整個字符串的前一部分創建索引 - 前綴索引面試
alter table SUser add index index2(email(6));
方式 2 相較於 方式 1 來講,利用前綴索引,佔用的空間更小。但有可能形成性能的損失,讀取數據的次數變多。sql
假設在 user 表中存在2986706524@gmail.com, 2986706524@qq.com , 2986706524@xxx.com, 三條記錄。網絡
有這樣一條語句 select id,name,email from SUser where email='2986706524@xxx.com';ide
使用 index1 索引時,流程以下:函數
使用 index2 索引:性能
看這個過程,很容易發現,前綴索引會增長查詢語句讀取數據的次數。學習
但若是將前綴索引的 email(6) 改爲 email(7),就會減小查詢的次數,對應在主鍵索引上只搜索一次。這就說明,若是能合適的設置前綴索引的長度,就能在空間和效率上取得平衡。
如何找到合適的前綴索引長度
在創建索引時,應該去關注區分度,區分度越高,則說明重複的鍵值越少。
能夠經過執行查詢來統計列上有多少不一樣的值。
mysql> select count(distinct email)as L, 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;
接着肯定業務上能夠接受的順勢區分度,好比 5%, 用 L 的數量 * 區分度比例(1-5%=95%),而後看在 L4 到 L7 中哪一個知足。
前綴索引的影響
在以前覆蓋索引的文章中,若是查詢的列的信息被包含在二級索引上,那麼就能夠避免回表的過程,進而減小查詢次數,提供效率。但若是在創建索引時,使用了前綴索引,那麼不管滿不知足覆蓋索引的規則,都會回表。由於系統不能肯定前綴索引是否截取了完成信息,進而必須作一次判斷。
也就是說,前綴索引除了會增長查詢語句的次數,還會禁止使用覆蓋索引。
對於郵箱這類的字符串來講,因爲前幾位有較大的區分度,因此用前綴索引還不錯。但若是是區分度很差的狀況,好比身份證,前 6 位都是地址碼,不少人都會同樣。這時若是想要使用前綴索引,就須要至少 12 位以上,對應查詢效率和空間都不是很合適。
一個比較好的辦法是將字符串倒序存儲,將區分度高的字符開頭。
例如:
mysql> select field_list from t \ where id_card = reverse('input_id_card_string');
在網絡傳輸時,CRC - 循環冗餘校驗被用於檢驗文件。對應在 MySQL 裏也有這個函數,crc32().
該函數的返回範圍是 0-4294967296 也就是 4 字節,相對於其餘字符串來講,屬於較短的長度。
在建立表時,可再建立一個整數字段,來保存這類字符串,如身份證的校驗碼(crc32()的返回值), 併爲該字段建立索引。
如:
mysql> alter table t add id_card_crc int unsigned, \ add index(id_card_crc);
在插入記錄時,將 crc32() 的結果插入到記錄中。
但因爲 crc32() 只有 32 位的特性,容易發生 hash 碰撞,就是說可能兩個字符串通過計算後獲得相同的驗證碼。這時就存在衝突,因此還須要判斷下查詢的值是否一致。
如:
mysql> select field_list from t where \ id_card_crc=crc32('input_id_card_string') and \ id_card='input_id_card_string'
咱們知道,MySQL 中使用的是 B+ 樹來存儲索引的,這天然就是有序的,因此前綴查詢就支持範圍查詢。
而 Hash 字段和倒序查詢兩種方式就不行了,倒序查詢是按照倒序字符串存儲的,而 hash 字段和字符串自己也沒有關係,這就意味着這兩種方式是不支持範圍查詢的。
在佔用空間上來講,倒序存儲佔用的是和普通索引的同樣的空間。而 hash 字段,須要增長一個字段來存在 hash 校驗碼。
在 CPU 消耗,倒序時,每次讀和寫都須要調用 reverse 函數。hash 方式須要額外調用 crc32() 函數。兩個函數實現來看,reverse 函數 CPU 消耗會少些。
在查詢效率上,hash 字段查詢性能更好穩定些。雖然可能存在衝突的狀況,但機率很小。而倒序存儲仍是用前綴索引的方式,會額外增長掃描行數。
總結一下,通常提升查詢字符串的效率有以下方式: