1. 程式人生 > >mysql 優化系列之欄位型別選取

mysql 優化系列之欄位型別選取

mysql  優化是一個很有意思的話題,可以從很多方面來說,大到伺服器叢集,應用體系架構等,小到欄位型別選擇,儲存引擎的選擇等,隨著mysql的發展,到目前(最新版本是8.0,筆者5.7)Innodb 已是預設的儲存引擎(mysql 5.5 已將InnoDB作為預設儲存引擎),所以儘量選擇使用InnoDB 作為預設的儲存引擎,如果想要使用myisam 儲存引擎的全文索引特性 ,建議使用InnoDB + Sphinx  組合,而不是使用支援全文索引的MyISAM,這裡借用mysql 高效能第三版書中一句話,"除非需要用到某些InnoDB不具備的特性,並且沒有其他辦法可以替代,否則都應該優先選擇InnoDB引擎",來結束對儲存引擎選擇問題的概述。下面就說下欄位型別的選擇問題。

主要有以下幾個原則可作為參考:

  • 1. 選擇的列儘可能的佔用少的儲存空間

          這樣做的目的是,儘可能減小佔用空間,以免在資料量大時查詢造成大量的磁碟IO開銷。當我們在需要儲存年齡,性別這些類似的應用場景中,應該選擇tinyint 來儲存,而不是int 。在處理日期的時候,也應該遵循這一原則,比如需要儲存使用者出生日期,應該選擇date型別。

這裡說下儲存日期時間資料的注意事項:

不要使用字串型別來儲存日期時間資料 日期時間型別通常比字串佔用的儲存空間小 日期時間型別在進行查詢過濾時可以利用日期來進行對比 日期時間型別還有著豐富的處理函式,可以方便的對日期時間型別進行計算 使用int儲存日期時間不如使用Timestamp型別

  • 資料型別的整合最好固定長度

        除此之外,需要儲存使用者密碼等長度值近似的字元時,應該優先考慮char 資料型別,因為char 是定長,varchar 是變長,mysql  處理char  比 varchar 要快一點。char型別的最大寬度為255 位元組,varchar 最大寬度為 65535 個位元組 。varchar列的最大長度小於255則只佔用一個額外位元組用於記錄字串長度,列的最大長度大於255則只佔用兩個額外位元組用於記錄字串長度。當在專案中能確定使用者某個欄位長度不會超過varchar 所能儲存的最大長度,單位了以防萬一而不得不使用更大的資料型別的是時候,也應該遵循這一原則,比如我能確定使用者所填資料不會超過varchar 所能儲存的最大長度,但為了防止使用者瞎操作,出現異常,而採用了text 型別來儲存,後來還是採用了medium text 來儲存。

  • 選擇的列儘可能的使用整數

        在生活中我們用到小數的應用場景很常見,比如:15.8元,100.2kg等等。在專案中,諸如入此類需要儲存小數的問題,應優先考慮用整數來儲存,而不是小數。下面 ,先來看一下,在mysql 中,浮點數資料型別特點:

列型別 儲存空間 是否精確型別
float 4 個位元組
double  8個位元組
decimal 每4個位元組存9個數字,小數點佔一個位元組

首先存整數和存小數,所佔據空間是一樣的(這是隻拿int 和float 來說),甚至更小。

其次浮點數運算會有精度丟失問題(decimal暫不考慮)。

當我們需要對該表的qty這個欄位做運算的時候有時會出現浮點數精度丟失問題。

由於上表的qty 這個欄位資料型別是doublel 型的,所以在做運算時會產生精度問題,從而在業務層做處理時造成不必要的麻煩(比如需要對計算結果取整或保留兩位小數)。當然你可能會說為什麼不用decimal 來儲存呢?是的,用decimal 來儲存確實能規避浮點數精度丟失問題,但是有一個問題用decimal 會比較慢,而且decimal 也不是必須的,比如上面提到的應用場景,在儲存錢的問題的時候,我們可以精確到分,比如:15.8元,在資料庫中儲存可以儲存為1580分,重量kg可以精確到克(g),這樣就能很好的規避浮點數精度問題,還能減少儲存空間的浪費。

還有一個應用場景就是ip地址的儲存,在mysql 中有兩個函式,inet_aton() 和 inet_ntoa() ,這兩個函式可以實現IP和數字間的轉換,所以在儲存ip地址的適用應考慮適用整數。

在PHP中可以使用,ip2long()  和 long2ip() 完成類似的操作。

當然以上原則只是一個參考 ,最主要還是根據業務來做相應的調整。