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

2021-08-28 11:59:25 字數 2917 閱讀 2109

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

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

更小的資料型別通常更快,因為它們占用更少的磁碟、記憶體和cpu快取,並且處理時需要的cpu週期也更少。當我們在需要儲存年齡,性別這些類似的應用場景中,應該選擇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),這樣就能很好的規避浮點數精度問題,還能減少儲存空間的浪費。

因為需要額外的空間和計算開銷,所以應該盡量只在對小數進行精確計算時才使用decimal-例如儲存財務資料。但在資料量比較大的時候,可以考慮使用 bigin代替decimal,將需要儲存的貨幣單位根據小數的位數乘以相應的倍數即可。假設要儲存財務資料精確到萬分之一分,則可以把所有金額乘以一百萬,然後將結果儲存在 bigint裡,這樣可以同時避免浮點儲存計算不精確和 decimal精確計算代價高的問題。

還有乙個應用場景就是ip位址的儲存,整型比字串操作代價更低,因為字符集和校對規則(排序規則)使字元比較比整型更複雜。在mysql 中有兩個函式,inet_aton() 和 inet_ntoa() ,這兩個函式可以實現ip和數字間的轉換,所以在儲存ip位址的適用應考慮適用整數。

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

很多表都包含可為null(空值)的列,即使應用程式並不需要儲存nul也是如此,這是因為可為null是列的預設屬性。通常情況下最好指定列為 not null,除非真的需要儲存null值。

如果查詢中包含可為nul的列,對mysql來說更難優化,因為可為null的列使得索引、索引統計和值比較都更複雜。可為nul的列會使用更多的儲存空間,在mysql裡也需要特殊處理。當可為null的列被索引時,每個索引記錄需要乙個額外的位元組,在 myisam裡甚至還可能導致固定大小的索引(例如只有乙個整數列的索引)變成可變大小的索引。

通常把可為nul的列改為 not null帶來的效能提公升比較小,所以(調優時)沒有必要首先在現有 schema中查詢並修改掉這種情況,除非確定這會導致問題。但是,如果計畫在列上建索引,就應該盡量避免設計成可為nul的列。

當然也有例外,例如值得一提的是, innodb使用單獨的位(bit)儲存nul值,所以對於稀疏資料(很多值為null,只有少數行的列有非null值)有很好的空間效率。但這一點不適用於 myisam。

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

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

mysql 優化是乙個很有意思的話題,可以從很多方面來說,大到伺服器集群,應用體系架構等,小到字段型別選擇,儲存引擎的選擇等,隨著mysql的發展,到目前 最新版本是8.0,筆者5.7 innodb 已是預設的儲存引擎 mysql 5.5 已將innodb作為預設儲存引擎 所以盡量選擇使用innod...

mysql欄位型別優化

選型原則 在保證足夠用的前提下盡量選擇最小型別!儲存人的年齡應該使用哪種資料型別?答 使用 tinyint 型別 無符號型 儲存烏龜的年齡應該使用哪種資料型別?答 使用 smallinit 型別 無符號型 儲存乙個 1500 萬資料的資料表其主鍵 id應該選擇哪種資料型別?答 使用 mediumin...

mysql欄位型別解析 MySQL欄位型別最全解析

前言 要了解乙個資料庫,我們必須了解其支援的資料型別。mysql 支援大量的字段型別,其中常用的也有很多。前面文章我們也講過 int 及 varchar 型別的用法,但一直沒有全面講過字段型別,本篇文章我們將把字段型別一網打盡,講一講常用字段型別的用法。常用的字段型別大致可以分為數值型別 字串型別 ...