篇2介紹了 MySQL 幾種常用的數(shù)據(jù)類型,并介紹了同種數(shù)據(jù)類型下具體類型的區(qū)別,并在最后總結(jié)了應(yīng)當如何根據(jù)具體的業(yè)務(wù)場景選擇最合適的數(shù)據(jù)類型來建立 MySQL 數(shù)據(jù)表。
1 - MySQL 數(shù)據(jù)類型
(一) 整數(shù)
整數(shù)類型 | 存儲空間 | 字節(jié)長度 |
---|---|---|
TinyInt | 8 | 1 |
SmallInt | 16 | 2 |
MediumInt | 24 | 3 |
Int | 32 | 4 |
BigInt | 64 | 8 |
它們可以存儲的值的范圍從 -2^(N-1) 到 2^(N-1) - 1夕土,N為存儲空間的位數(shù)。整數(shù)類型有可選的 Unsigned 屬性时甚,表示不允許負值隘弊,這大致可以使正數(shù)的上限提高一倍哈踱。例如 TinyInt Unsigned 可以存儲的范圍是 0 ~ 255荒适,而 TINYINT 的存儲范圍是 -128 ~ 127。
注意點:
int(M) M指示最大顯示寬度(最大有效顯示寬度是255)开镣,顯示寬度與存儲大小或類型包含的值的范圍無關(guān)刀诬。對于存儲和計算來說,Int(2) 和 Int(4)是相同的邪财,它們均占用4個字節(jié)陕壹,存儲范圍(-2^31 到 2^31- 1),只是在表示數(shù)字25時树埠,int(2)是25糠馆,int(4)是0025,即不足寬度會用在左邊用0補充怎憋。
(二) 浮點數(shù)
浮點數(shù)類型 | 字節(jié)長度 | 用法 |
---|---|---|
Float(M,D) | 4 | 單精度浮點數(shù)又碌,D<=24為默認Float,D>24則轉(zhuǎn)化為Double |
Double(M,D) | 8 | 雙精度浮點數(shù) |
Decimal(M,D) | M+1/M+2 | 未打包的浮點數(shù),計算中Decimal會轉(zhuǎn)換為Double |
-
單精度和雙精度的區(qū)別:
單精度 Float绊袋,一般在計算機中存儲占用4字節(jié)毕匀,也32位,有效位數(shù)為7位癌别;雙精度 Double 在計算機中存儲占用8字節(jié)皂岔,64位,有效位數(shù)為16位展姐。原因:不管float還是double 在計算機上的存儲都遵循IEEE規(guī)范躁垛,使用二進制科學計數(shù)法,都包含三個部分:符號位圾笨,指數(shù)位和尾數(shù)部分教馆。其中float的符號位,指數(shù)位墅拭,尾數(shù)部分分別為1, 8, 23活玲。 雙精度分別為1, 11, 52。
精度主要取決于尾數(shù)部分的位數(shù)舒憾,float為23位镀钓,除去全部為0的情況以外,最小為2的-23次方镀迂,約等于1.19乘以10的-7次方丁溅,所以float小數(shù)部分只能精確到后面6位,加上小數(shù)點前的一位探遵,即有效數(shù)字為7位窟赏。類似,double 尾數(shù)部分52位箱季,最小為2的-52次方涯穷,約為2.22乘以10的-16次方,所以精確到小數(shù)點后15位藏雏,有效位數(shù)為16位拷况。
-
Decimal的用法:
因為 Decimal 相比于 Float 和 Double 需要額外的空間和計算開銷,所以盡量只在對小數(shù)進行精確計算時才使用掘殴,例如存儲財務(wù)數(shù)據(jù)赚瘦。但在數(shù)據(jù)量比較大的時候,可以考慮使用 BigInt 代替 Decimal奏寨,將需要存儲的貨幣單位根據(jù)小數(shù)的位數(shù)乘以相應(yīng)的倍數(shù)即可起意。
(三) 字符串類型
- VarChar
VarChar 用于存儲可變長字符串,比定長類型更節(jié)省空間病瞳。VarChar 需要使用1或2個額外字節(jié)記錄字符串的長度揽咕。VarChar 節(jié)省了存儲空間,對性能也有幫助仍源,但是由于行是變長的心褐,在Update時可能使行變得比原來更長,這就導致需要做額外的工作笼踩,對此不同的存儲引擎的有著自己的處理方式逗爹。
VarChar 的適合應(yīng)用于這樣的場景:字符串列的最大長度比平均長度大很多;列的更新很少嚎于,所以碎片不是問題掘而;使用了UTF-8這樣復雜的字符集,每個字符都使用不同的字節(jié)數(shù)進行存儲于购。
- Char
Char 類型是定長的袍睡,根據(jù)定義的字符串長度分配足夠的空間。Char 適合存儲很短的字符串肋僧,或者所有值都接近同一個長度斑胜。
例如控淡,存儲密碼的MD5值,因為這是一個定長的值止潘;經(jīng)常變更的數(shù)據(jù)掺炭,Char 也比 VarChar 更好,因為定長的 Char 類型不容易產(chǎn)生碎片凭戴;對于非常短的列涧狮,Char 比 VarChar 在存儲空間上也更有效率,比如用 char(1) 來存儲只有Y和N的值么夫,如果采用單字節(jié)字符集只需要一個字節(jié)者冤,但是 varchar(1) 卻需要兩個字節(jié),因為還有一個記錄長度的額外字節(jié)档痪。
使用 varchar(5) 和 varchar(200) 存儲 'hello' 的空間開銷是一樣的涉枫,那么使用更短的列有什么優(yōu)勢嗎?
事實證明有很大的優(yōu)勢钞它。更長的列會消耗更多的內(nèi)存拜银,因為 MySQL 通常會分配固定大小的內(nèi)存塊來保存內(nèi)部值殊鞭。尤其是使用內(nèi)存臨時表進行排序或操作時會特別糟糕遭垛。在利用磁盤臨時表進行排序時也同樣糟糕。所以最好的策略是只分配真正需要的空間操灿。
(四) 日期和時間類型
DataTime
能保存大范圍的值锯仪,從 1001 年到 9999 年,精度為秒趾盐。它把日期和時間封裝到格式為 YYYYMMDDHHMMSS 的整數(shù)中庶喜,與時區(qū)無關(guān)。使用 8 個字節(jié)的存儲空間救鲤,例如 “2017-03-31 10:46:37”久窟。這是 ANSI 標準定義的日期和時間表示方法。TimeStamp
TimeStamp 只使用 4 個字節(jié)的存儲空間本缠,因此范圍比 DataTime 小斥扛,只能表示從 1970 年到 2038 年。如果在多個時區(qū)存儲或訪問數(shù)據(jù)丹锹,TimeStamp 和 DataTime 的行為將很不一樣稀颁。前者提供的值與時區(qū)有關(guān)系,后者則保留文本表示的日期和時間楣黍。
TimeStamp 也有 DataTime 沒有的特殊屬性匾灶。默認情況下,如果插入時沒有指定第一個 TimeStamp 列的值租漂,MySQL 則設(shè)置這個列的值為當前時間阶女。TimeStamp 列默認為 NOT NULL颊糜,這也和其他數(shù)據(jù)類型不一樣。
通常應(yīng)該盡量使用 TimeStamp秃踩,因為它比 DataTime 空間效率更高芭析。
以上只是介紹了筆者在日常開發(fā)中最經(jīng)常使用的一些數(shù)據(jù)類型,相信這些類型應(yīng)該可以滿足你最基本的業(yè)務(wù)開發(fā)需求吞瞪。
2 - 數(shù)據(jù)類型優(yōu)化策略
(一) 盡量使用最小數(shù)據(jù)類型
更小的數(shù)據(jù)類型通常更快馁启,因為其占用更少的磁盤、內(nèi)存和 CPU 緩存芍秆,并且處理時需要的 CPU 周期也更少惯疙。但是要確保沒有低估需要存儲的值的范圍,因為表中多個地方增加數(shù)據(jù)類型的范圍是一個非常耗時的操作妖啥。如果無法確定哪個數(shù)據(jù)類型是最好的霉颠,就選擇你認為不會超過范圍的最小類型。
(二) 簡單就好
簡單數(shù)據(jù)類型的操作需要更少的 CPU 周期荆虱。例如蒿偎,整型比字符操作代價更低,因為字符集和校對規(guī)則使字符比較比整型比較更復雜怀读。有兩個點值得注意诉位,一是應(yīng)該使用 MySQL 內(nèi)建的類型而不是字符串來存儲日期和時間,二是應(yīng)該用整型存儲 IP 地址菜枷。
(三) 盡量避免 NULL
通常情況下最好指定列為 NOT NULL苍糠,除非真的需要存儲 NULL 值。因為如果查詢中包含可為 NULL 的列啤誊,對 MySQL 來說更難優(yōu)化岳瞭,因為可為 NULL 的列使得索引、索引統(tǒng)計和值比較都更復雜蚊锹。可為 NULL 的列會使用更多的存儲空間瞳筏,在MySQL里也需要特殊處理。當可為 NULL 的列被索引是牡昆,每個索引記錄需要一個額外的字節(jié)姚炕。
大家好,我是彬彬醬迁杨,目前在騰訊從事Web后端開發(fā)钻心。
菜鳥必知的 MySQL 知識專題整理了關(guān)于 MySQL 的基礎(chǔ)知識,適合大家進行入門級學習铅协,這個專題現(xiàn)包含下列文章:
菜鳥必知的 MySQL 知識(一)—— 基礎(chǔ)知識
菜鳥必知的 MySQL 知識(二)—— 數(shù)據(jù)類型優(yōu)化
菜鳥必知的 MySQL 知識(三)—— 索引優(yōu)化