mysql索引使用經驗總結

小糖糖_發表於2019-05-13

字串建立索引(字首索引)

比如郵箱或者身份證號的儲存,使用字首索引,字首索引長度的選擇。

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 。反而增加維護成本。但是對於大資料量的寫的操作,效能會有很大的提升。

隱式轉換

由於資料庫型別不匹配可能會涉及到隱式轉換,隱式轉換之後索引會失效。所以當建立了索引查詢依舊很慢的時候,需要注意這一點。工作中也多次碰到過。

最左字首索引

暫無。



相關文章