1. 程式人生 > 實用技巧 >7.字首索引

7.字首索引

7.字首索引

使用字首索引,定義好長度,就可以做到既節省空間(定義索引的欄位越短,約減少索引樹中頁裡面的空間。可以聯想主鍵不宜定義過長的欄位,因為所有二級索引都需要關聯主鍵的欄位值!!),又不用額外增加太多的查詢成本(減少回表的次數就是減少IO!!!)。

mysql> select count(distinct email) as L from SUser;

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;

這個語句可以算出每一列前L個位元組的不同的數量,來比較區分度,區分度越高,就越能減少回表的次數。

字首索引對覆蓋索引的影響

完全影響了覆蓋所有,不論字首索引在定義的時候截取了多長的位元組。在查詢中如果只包含主鍵及字首索引的欄位,都會回表到主鍵索引!!!!

因為系統並不確定字首索引的定義是否截斷了完整資訊。也就是說,使用字首索引就用不上覆蓋索引對查詢效能的優化了,這也是你在選擇是否使用字首索引時需要考慮的一個因素。

其他方式

像長的欄位並且前面部分的區分度較高的話推薦使用字首索引,但是像身份證這種又長,而且前面區分度低的,用字首索引就沒效果了。因為索引選取的越長,佔用的磁碟空間就越大,相同的資料頁能放下的索引值就越少,搜尋的效率也就會越低

,所以推薦使用:

​ 第一種方式是使用倒序儲存。如果你儲存身份證號的時候把它倒過來存,每次查詢的時候,你可以這麼寫:

mysql> select field_list from t where id_card = reverse('input_id_card_string');

當然了,實踐中你不要忘記使用 count(distinct) 方法去做個驗證。判斷某一列的區分度

​ 第二種方式是使用 hash 欄位。你可以在表上再建立一個整數字段,來儲存身份證的校驗碼(hash身份證後得到的hash值),同時在這個欄位上建立索引。

mysql> alter table t add id_card_crc int unsigned, add index(id_card_crc);

然後每次插入新記錄的時候,都同時用 crc32() 這個函式得到校驗碼填到這個新欄位。由於校驗碼可能存在衝突,也就是說兩個不同的身份證號通過 crc32() 函式得到的結果可能是相同的,所以你的查詢語句 where 部分要判斷 id_card 的值是否精確相同

mysql> select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'

​ 接下來,我們再一起看看使用倒序儲存和使用 hash 欄位這兩種方法的異同點。首先,

它們的相同點是,都不支援範圍查詢。倒序儲存的欄位上建立的索引是按照倒序字串的方式排序的,已經沒有辦法利用索引方式查出身份證號碼在[ID_X, ID_Y]的所有市民了。同樣地,hash 欄位的方式也只能支援等值查詢

它們的區別,主要體現在以下三個方面:

1.從佔用的額外空間來看,倒序儲存方式在主鍵索引上,不會消耗額外的儲存空間,而 hash 欄位方法需要增加一個欄位。當然,倒序儲存方式使用 4 個位元組的字首長度應該是不夠的,如果再長一點,這個消耗跟額外這個 hash 欄位也差不多抵消了。

2.在 CPU 消耗方面,倒序方式每次寫和讀的時候,都需要額外呼叫一次 reverse 函式,而 hash 欄位的方式需要額外呼叫一次 crc32() 函式。如果只從這兩個函式的計算複雜度來看的話,reverse 函式額外消耗的 CPU 資源會更小些。

3.從查詢效率上看,使用 hash 欄位方式的查詢效能相對更穩定一些。因為 crc32 算出來的值雖然有衝突的概率,但是概率非常小,可以認為每次查詢的平均掃描行數接近 1。而倒序儲存方式畢竟還是用的字首索引的方式,也就是說還是會增加掃描行數