兩種:
- 全字段索引
- 前綴索引
舉例:
mysql> create table SUser(
ID bigint unsigned primary key,
email varchar(64),
...
)engine=innodb;
可以對 email 字段創建全字段索引,或者前綴索引。
mysql> alter table SUser add index index1(email);
或
mysql> alter table SUser add index index2(email(6));
區別
1、全字段索引佔用空間大,前綴索引佔用空間小;
2、全字段索引查詢效率高,前綴索引則會增加額外的記錄掃描次數。
執行過程
select id,name,email from SUser where email='[email protected]';
1、全字段索引
① 從 index1 索引樹中找到索引值是 [email protected]
的記錄,然後得到主鍵值;
② 根據主鍵值獲取到該行的完整數據(回表),再判斷 email 是否滿足條件,將這行記錄加入結果集;
③ 沿着索引樹繼續查找下一條滿足條件的數據,若不滿足,循環結束;
2、前綴索引
① 從 index2 索引樹上查找索引值是 zhangs
的記錄,找到一條後,得到主鍵值;
② 根據主鍵值獲取到該行的完整數據(回表),再判斷 email 是否滿足條件,將這行記錄加入結果集;
③ 沿着索引樹繼續查找下一條滿足條件的數據,發現仍然滿足條件,重複上面的操作;
④ 重複上一步,直到在 index2 上取到的值不滿足條件,循環結束。
很明顯,使用前綴索引,導致查詢次數增多。
如何減少前綴索引查詢次數?
區分度,區分度越高,前綴重複的可能性越小,進而,查詢次數就越少。
通過如下語句,可以查詢到不通前綴長度,分別有多少個不同的值:
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;
自己可以預先設定一個可以接受的重複比例,比如大於 L * 95%。
前綴索引對覆蓋索引的影響
使用前綴索引將無法利用覆蓋索引的優化。
查詢時,系統並不確定前綴索引的定義是否截斷了完整信息。
前綴索引的優化
1、倒序存儲
適合字段值前面部分重複度高,後半部分重複度低,這時可以倒序存儲數據。
查詢時可以這麼寫:
mysql> select field_list from t where id_card = reverse('input_id_card_string');
2、做 hash
新增一個字段,專門存儲字段的 hash 值:
mysql> alter table t add id_card_crc int unsigned, add index(id_card_crc);
每次插入數據時,都要調用 crc32()
這個函數得到校驗碼填到這個新字段。
這個字段有可能重複,需要聯合判斷 id_card 的值是否精確相同。
mysql> select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'
二者的區別
1、都不支持範圍查詢
2、hash 字段需要額外的空間
3、CPU 消耗:倒序插入時需要額外調用 reverse 函數,hash 需要調用 crc32() 函數。reverse 函數消耗的 CPU 更小一些;
4、hash 字段方式的查詢效率更高,因爲計算出來的 hash 值重複的可能性較小,掃描次數接近於 1
總結
1、直接創建完整索引,這樣可能比較佔用空間;
2、創建前綴索引,節省空間,但會增加查詢掃描次數,並且不能使用覆蓋索引;
3、倒序存儲,再創建前綴索引,用於繞過字符串本身前綴的區分度不夠的問題;
4、創建 hash 字段索引,查詢性能穩定,有額外的存儲和計算消耗,跟第三種方式一樣,都不支持範圍掃描。
如何選擇?
當數據量大時,一個學校每年預估 2 萬新生,50 年才 100 萬記錄,能節省多少空間,直接全字段索引。省去了開發轉換及侷限性風險,碰到超大量迫不得已再用後兩種辦法。從業務量預估優化和收益,這不失爲一個不錯的想法。
關注本公衆號,後臺回覆「2018」即可獲取傳智播客 2018 最新 Python 和 Java 教程。
公衆號提供CSDN資源免費下載服務!