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() 完成類似的操作。
當然以上原則只是一個參考 ,最主要還是根據業務來做相應的調整。