字串建立索引(字首索引)
比如郵箱或者身份證號的儲存,使用字首索引,字首索引長度的選擇。
select
count(distinct left(email,4)) as a,
count(distinct left(email,4)) as b,
count(distinct left(email,4)) as c,from table 複製程式碼
注意:字首索引會使覆蓋索引失效,因為字首索引只有部分資料,需要回表找到完整資料。
對於區分度不太好的,例如身份證號。之後後面幾位才有區分度。那麼如何儲存?
- 倒序儲存之後取字首索引
select * from table where card = reverse('card_string')複製程式碼
- 使用hash欄位儲存(查詢的時候必須使用等於,精確匹配)
select * from t where card = crc32('card_string')複製程式碼
上面2個缺點是都不支援範圍查詢。
總結:
- 直接建立索引,空間佔用大。
- 字首索引,節省空間,但是覆蓋索引會失效。
- 對於字首區分度不高的使用,倒序儲存,不支援範圍查詢。
- 建立hash欄位索引,效能穩定,也不支援範圍查詢。
考慮一種場景:使用者名稱+密碼的登入。因為只有單資料查詢沒有範圍查詢場景,一般可以吧多個欄位hash字後儲存。
唯一索引和普通索引的選取
前提:在業務保證一致的情況下,如何選擇?
查詢
select * from where a = '1'; 複製程式碼
a為唯一索引:mysql會在a索引樹上找到1這條資料的id,回表查出所有資料。
a為普通索引:mysql在a索引上找到1之後會接著找下一個,直到下一個不為1,然後同樣回表查出資料返回。如果查下一個資料的時候正好在下一頁,會涉及到一次io,但是一個資料頁一般會放進千個資料,索引概率相對較小。
更新
更新資料的時候,如果資料在資料頁中就直接更新,否則存入change buffer中,就不會從磁碟中讀取資料。下次查詢訪問資料也的時候,將資料也讀入記憶體,執行change buffer 中與這個頁面的merge操作。通過這種方式保證一致性。資料庫也會定期執行merge操作。
update table set a = a+1 where xxx;複製程式碼
由上可知:
當更新的資料在記憶體中的話:
- 唯一索引:判斷資料唯一,直接更新記憶體資料。
- 普通索引:直接更新記憶體資料。
更新資料不在記憶體:
- 唯一索引:資料讀入記憶體,(io)判斷是否是否重複,不重複就插入
- 普通索引:直接寫change buffer
場景:如果寫入之後立馬會讀,就沒必要使用change buffer 。反而增加維護成本。但是對於大資料量的寫的操作,效能會有很大的提升。
隱式轉換
由於資料庫型別不匹配可能會涉及到隱式轉換,隱式轉換之後索引會失效。所以當建立了索引查詢依舊很慢的時候,需要注意這一點。工作中也多次碰到過。
最左字首索引
暫無。