菜鳥必知的 MySQL 知識(二)—— 數據類型優化

篇2介紹了 MySQL 幾種常用的數據類型,并介紹了同種數據類型下具體類型的區別,并在最后總結了應當如何根據具體的業務場景選擇最合適的數據類型來建立 MySQL 數據表。

1 - MySQL 數據類型

(一) 整數
整數類型 存儲空間 字節長度
TinyInt 8 1
SmallInt 16 2
MediumInt 24 3
Int 32 4
BigInt 64 8

它們可以存儲的值的范圍從 -2^(N-1) 到 2^(N-1) - 1,N為存儲空間的位數。整數類型有可選的 Unsigned 屬性,表示不允許負值,這大致可以使正數的上限提高一倍。例如 TinyInt Unsigned 可以存儲的范圍是 0 ~ 255,而 TINYINT 的存儲范圍是 -128 ~ 127

注意點
 int(M) M指示最大顯示寬度(最大有效顯示寬度是255),顯示寬度與存儲大小或類型包含的值的范圍無關。對于存儲和計算來說,Int(2) 和 Int(4)是相同的,它們均占用4個字節,存儲范圍(-2^31 到 2^31- 1),只是在表示數字25時,int(2)是25,int(4)是0025,即不足寬度會用在左邊用0補充。

(二) 浮點數
浮點數類型 字節長度 用法
Float(M,D) 4 單精度浮點數,D<=24為默認Float,D>24則轉化為Double
Double(M,D) 8 雙精度浮點數
Decimal(M,D) M+1/M+2 未打包的浮點數,計算中Decimal會轉換為Double
  • 單精度和雙精度的區別
     單精度 Float,一般在計算機中存儲占用4字節,也32位,有效位數為7位;雙精度 Double 在計算機中存儲占用8字節,64位,有效位數為16位。原因:不管float還是double 在計算機上的存儲都遵循IEEE規范,使用二進制科學計數法,都包含三個部分:符號位,指數位和尾數部分。其中float的符號位,指數位,尾數部分分別為1, 8, 23。 雙精度分別為1, 11, 52。 
     精度主要取決于尾數部分的位數,float為23位,除去全部為0的情況以外,最小為2的-23次方,約等于1.19乘以10的-7次方,所以float小數部分只能精確到后面6位,加上小數點前的一位,即有效數字為7位。類似,double 尾數部分52位,最小為2的-52次方,約為2.22乘以10的-16次方,所以精確到小數點后15位,有效位數為16位
  • Decimal的用法: 
     因為 Decimal 相比于 Float 和 Double 需要額外的空間和計算開銷,所以盡量只在對小數進行精確計算時才使用,例如存儲財務數據。但在數據量比較大的時候,可以考慮使用 BigInt 代替 Decimal,將需要存儲的貨幣單位根據小數的位數乘以相應的倍數即可。
(三) 字符串類型
  • VarChar

VarChar 用于存儲可變長字符串,比定長類型更節省空間。VarChar 需要使用1或2個額外字節記錄字符串的長度。VarChar 節省了存儲空間,對性能也有幫助,但是由于行是變長的,在Update時可能使行變得比原來更長,這就導致需要做額外的工作,對此不同的存儲引擎的有著自己的處理方式。

VarChar 的適合應用于這樣的場景:字符串列的最大長度比平均長度大很多;列的更新很少,所以碎片不是問題;使用了UTF-8這樣復雜的字符集,每個字符都使用不同的字節數進行存儲。

  • Char

Char 類型是定長的,根據定義的字符串長度分配足夠的空間。Char 適合存儲很短的字符串,或者所有值都接近同一個長度。

例如,存儲密碼的MD5值,因為這是一個定長的值;經常變更的數據,Char 也比 VarChar 更好,因為定長的 Char 類型不容易產生碎片;對于非常短的列,Char 比 VarChar 在存儲空間上也更有效率,比如用 char(1) 來存儲只有Y和N的值,如果采用單字節字符集只需要一個字節,但是 varchar(1) 卻需要兩個字節,因為還有一個記錄長度的額外字節。

使用 varchar(5) 和 varchar(200) 存儲 'hello' 的空間開銷是一樣的,那么使用更短的列有什么優勢嗎?
 事實證明有很大的優勢。更長的列會消耗更多的內存,因為 MySQL 通常會分配固定大小的內存塊來保存內部值。尤其是使用內存臨時表進行排序或操作時會特別糟糕。在利用磁盤臨時表進行排序時也同樣糟糕。所以最好的策略是只分配真正需要的空間。

(四) 日期和時間類型
  • DataTime
     能保存大范圍的值,從 1001 年到 9999 年,精度為秒。它把日期和時間封裝到格式為 YYYYMMDDHHMMSS 的整數中,與時區無關。使用 8 個字節的存儲空間,例如 “2017-03-31 10:46:37”。這是 ANSI 標準定義的日期和時間表示方法。

  • TimeStamp
     TimeStamp 只使用 4 個字節的存儲空間,因此范圍比 DataTime 小,只能表示從 1970 年到 2038 年。如果在多個時區存儲或訪問數據,TimeStamp 和 DataTime 的行為將很不一樣。前者提供的值與時區有關系,后者則保留文本表示的日期和時間。
     TimeStamp 也有 DataTime 沒有的特殊屬性。默認情況下,如果插入時沒有指定第一個 TimeStamp 列的值,MySQL 則設置這個列的值為當前時間。TimeStamp 列默認為 NOT NULL,這也和其他數據類型不一樣。

通常應該盡量使用 TimeStamp,因為它比 DataTime 空間效率更高。

以上只是介紹了筆者在日常開發中最經常使用的一些數據類型,相信這些類型應該可以滿足你最基本的業務開發需求。


2 - 數據類型優化策略

(一) 盡量使用最小數據類型

更小的數據類型通常更快,因為其占用更少的磁盤、內存和 CPU 緩存,并且處理時需要的 CPU 周期也更少。但是要確保沒有低估需要存儲的值的范圍,因為表中多個地方增加數據類型的范圍是一個非常耗時的操作。如果無法確定哪個數據類型是最好的,就選擇你認為不會超過范圍的最小類型。

(二) 簡單就好

簡單數據類型的操作需要更少的 CPU 周期。例如,整型比字符操作代價更低,因為字符集和校對規則使字符比較比整型比較更復雜。有兩個點值得注意,一是應該使用 MySQL 內建的類型而不是字符串來存儲日期和時間,二是應該用整型存儲 IP 地址。

(三) 盡量避免 NULL

通常情況下最好指定列為 NOT NULL,除非真的需要存儲 NULL 值。因為如果查詢中包含可為 NULL 的列,對 MySQL 來說更難優化,因為可為 NULL 的列使得索引、索引統計和值比較都更復雜。可為 NULL 的列會使用更多的存儲空間,在MySQL里也需要特殊處理。當可為 NULL 的列被索引是,每個索引記錄需要一個額外的字節。


大家好,我是彬彬醬,目前在騰訊從事Web后端開發。
菜鳥必知的 MySQL 知識專題整理了關于 MySQL 的基礎知識,適合大家進行入門級學習,這個專題現包含下列文章:
菜鳥必知的 MySQL 知識(一)—— 基礎知識
菜鳥必知的 MySQL 知識(二)—— 數據類型優化
菜鳥必知的 MySQL 知識(三)—— 索引優化


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容